Error codes
Every error the server returns is an ErrorResponse with a stable numeric code. Match on the code, never on the text. The error_message is a JSON object with the error's context, for example {"expected_version":4,"current_aggregate_version":6} on a concurrency conflict or {"leader_address":"10.0.0.2:10000"} on a not-leader.
Names below are the server constants in celeriant_msg/src/error_codes.rs. The .NET client exposes the same codes as ErrorResponse constants in PascalCase (WriteNotLeader), and the Rust client maps them to ServerError variants. Codes are sparse; gaps are unused.
Codes can still change before 1.0.
Read (1xxx)
| Code | Name | Meaning |
|---|---|---|
| 1000 | READ_UNAVAILABLE_VERSION | The requested version is below the first one still stored, usually because the stream was trimmed. The message carries requested and minimum_available. |
| 1001 | READ_AGGREGATE_NOT_EXISTS | No such aggregate. |
| 1002 | READ_CACHE_LOAD_LOCK_TIMEOUT | Loading the aggregate into cache timed out waiting on another loader. Retry. |
| 1003 | READ_CACHE_LOAD_FILE_SCAN | Disk scan failed while loading the aggregate into cache. |
| 1004 | READ_FETCH_DATABLOCKS | Failed to fetch data blocks from disk. |
| 1005 | READ_FETCH_METABLOCKS | Failed to fetch metadata blocks from disk. |
Write (2000-2013)
| Code | Name | Meaning |
|---|---|---|
| 2000 | WRITE_EMPTY_EVENTS_LIST | One of the aggregates in the write has no events. |
| 2001 | WRITE_ZERO_EVENT_TYPE | An event has event_type_major 0, which is reserved. |
| 2002 | WRITE_CLIENT_IDEMPOTENCY_VIOLATION | With idempotency enforced, the write's lowest client sequence is at or below the last committed sequence for this client on this aggregate. It proves the sequence is consumed for this (aggregate, client_id), not that your event consumed it: concurrent writers sharing a client id can take each other's sequences. Verify by point-reading the sequence. See what a 2002 proves and the idempotency guide. |
| 2003 | WRITE_OPTIMISTIC_CONCURRENCY_VIOLATION | expected_version does not match the aggregate's current version. Re-read and retry. See Optimistic concurrency. |
| 2004 | WRITE_FAILED_TO_SERIALISE_DATABLOCKS | The server could not serialise the write's events. |
| 2005 | WRITE_AGGREGATE_NOT_EXISTS | The aggregate does not exist and the write did not set allow_create. |
| 2006 | WRITE_AGGREGATE_RECREATE_NOT_ALLOWED | The aggregate was deleted without allow_recreate. |
| 2007 | WRITE_REPLICATION_ERROR | Replicating the write to the follower failed. |
| 2008 | WRITE_FSYNC_ERROR | The leader's fsync failed. |
| 2009 | WRITE_CACHE_AGGREGATE_CLIENT_ERROR | Internal cache error loading the client's sequence state or the schema cache. |
| 2010 | WRITE_AGGREGATE_EXISTS_CACHE_ERROR | Internal cache error checking whether the aggregate exists. |
| 2011 | WRITE_NOT_LEADER | The write hit a follower. The message carries leader_address when known. Client pools redirect automatically. See two-node cluster. |
| 2012 | WRITE_REPLICATION_BACKPRESSURE | The leader is shedding writes because replication is behind or just rolled back. Back off and retry. See troubleshooting. |
| 2013 | WRITE_INFLIGHT_DUPLICATE | Same check as 2002, but the earlier write with that sequence is still in flight: queued, or fsynced and not yet committed. It is not durable yet and can still roll back, so this is not success. Hold the sequence, back off, retry. It resolves to a clean write or a 2002. |
With idempotency enforced, the expected-version check runs before the sequence check. A retry of a write that already landed with expected_version set gets 2003, not 2002.
Schema (2020-2029)
| Code | Name | Meaning |
|---|---|---|
| 2020 | REGISTER_SCHEMA_ALREADY_EXISTS | A schema is already registered, or pending, for this org, aggregate type and event type major/minor. |
| 2021 | REGISTER_SCHEMA_INVALID | The schema did not parse or compile, or exceeds --max-schema-size-bytes. |
| 2022 | WRITE_SCHEMA_VALIDATION_FAILED | An event failed validation against its registered schema. The message names the event type and client sequence. |
| 2023 | WRITE_SCHEMA_COMPILATION_FAILED | The registered schema for this event type failed to compile when loaded, so writes of that type cannot be validated. Registering it again gets 2020. |
| 2024 | REGISTER_SCHEMA_UNSUPPORTED_TYPE | schema_type is not 0 (JSON), 1 (Avro) or 2 (Protobuf). |
| 2025 | REGISTER_SCHEMA_CACHE_LOAD_ERROR | Internal cache load failure for the schema registry. |
| 2026 | REGISTER_SCHEMA_FSYNC_ERROR | Fsync failed writing the schema. |
| 2027 | REGISTER_SCHEMA_CANNOT_ACCEPT_WRITES | This node is not the leader. Treated as not-leader; client pools redirect. |
| 2028 | REGISTER_SCHEMA_REPLICATION_ERROR | Replicating the registration to the follower failed. |
| 2029 | REGISTER_SCHEMA_COORDINATION_FAILED | Shard 0 registered the schema, then the fan-out to the other shards failed or timed out. The message carries failed_shard_count and total_shards. Not transient: shard 0 already holds the schema, so a plain retry gets 2020 and never repairs the shards that missed it. |
Trim (3xxx)
| Code | Name | Meaning |
|---|---|---|
| 3000 | TRIM_AGGREGATE_NOT_EXISTS | No such aggregate. |
| 3001 | TRIM_CACHE_ERROR | Internal cache error. |
| 3002 | TRIM_REPLICATION_ERROR | Replicating the trim failed. |
| 3003 | TRIM_FSYNC_ERROR | Fsync failed. |
| 3004 | TRIM_INDEX_OUT_OF_RANGE | keep_from_aggregate_version is past the aggregate's current version. |
| 3005 | TRIM_NOT_LEADER | The trim hit a follower. Client pools redirect. |
| 3006 | TRIM_REPLICATION_BACKPRESSURE | The leader is shedding load. Back off and retry. |
Delete (4xxx)
| Code | Name | Meaning |
|---|---|---|
| 4000 | DELETE_AGGREGATE_NOT_EXISTS | No such aggregate. |
| 4001 | DELETE_EMPTY_DELETE_LIST | The delete named no aggregates. The router rejects that first with 9002, so a client should not see 4001. |
| 4002 | DELETE_OPTIMISTIC_CONCURRENCY_VIOLATION | expected_version does not match. Re-read and retry. |
| 4003 | DELETE_CACHE_ERROR | Internal cache error. |
| 4004 | DELETE_REPLICATION_ERROR | Replicating the delete failed. |
| 4005 | DELETE_FSYNC_ERROR | Fsync failed. |
| 4006 | DELETE_NOT_LEADER | The delete hit a follower. Client pools redirect. |
| 4007 | DELETE_REPLICATION_BACKPRESSURE | The leader is shedding load. Back off and retry. |
Listing (5xxx)
| Code | Name | Meaning |
|---|---|---|
| 5000 | LIST_ORGS_DISK_READ | Listing orgs failed reading the WAL. |
| 5001 | LIST_AGGREGATE_TYPES_DISK_READ | Listing aggregate types failed reading the WAL. |
| 5002 | LIST_AGGREGATES_DISK_READ | Listing aggregates failed reading the WAL. |
Replication batch (6xxx)
Sent on the replication port, from follower to leader. Clients never see these.
| Code | Name | Meaning |
|---|---|---|
| 6000 | REPLICATION_BATCH_FSYNC | The follower's fsync of the batch failed. |
| 6001 | REPLICATION_BATCH_SERIALISE_DATABLOCKS | The follower could not re-serialise the leader's data blocks. |
| 6002 | REPLICATION_BATCH_WAL_SEQ_GAP | The batch's WAL sequences are not contiguous with the follower's log. |
Aggregate details (7xxx)
| Code | Name | Meaning |
|---|---|---|
| 7000 | EXISTS_CACHE_ERROR | Internal cache error. |
| 7001 | EXISTS_AGGREGATE_NOT_EXISTS | The aggregate does not exist. |
| 7002 | EXISTS_METABLOCK_READ_ERROR | Failed to read the aggregate's metadata blocks. |
Watch (8xxx)
| Code | Name | Meaning |
|---|---|---|
| 8000 | WATCH_REQUEST_INVALID | A watch request reached the shard's ordinary request path. An internal routing fault, not a problem with your filters. |
| 8001 | WATCH_LATENCY_TOO_HIGH | requested_latency_ms exceeds --max-requested-latency-ms. The message carries requested_ms and max_ms. |
| 8002 | WATCH_READ_IO | I/O error reading events for a notification. |
| 8003 | WATCH_READ_SERIALIZATION | Serialisation error building a notification. |
| 8004 | WATCH_READ_OTHER | Other internal error in the watch session. |
| 8005 | WATCH_TOO_MANY_SUBSCRIBERS | The shard is at its --max-watch-subscribers cap. The message carries active_subscribers and max_subscribers. |
Shard routing (9xxx)
| Code | Name | Meaning |
|---|---|---|
| 9000 | SHARD_ROUTING_NO_KEY | No routing key. The router checks for empty filters first and returns 9002, so this is defensive. |
| 9001 | SHARD_ROUTING_MULTIPLE_SHARDS | The write or delete keys, or the watch filter values, route to more than one shard (placement is id % num_shards). Nothing is split across shards. See Atomic multi-aggregate writes. |
| 9002 | SHARD_ROUTING_INCOMPATIBLE_FILTERS | The request cannot be routed: an empty write or delete, a shard_id at or past the shard count, or a watch without a filter on the routing dimension (e.g. no orgs when routing by org_id). The message says which. |
Identity and authentication (10xxx)
From the identify handshake. See Identity and authentication.
| Code | Name | Meaning |
|---|---|---|
| 10001 | IDENTIFY_INVALID_NONCE | The nonce is unparsable, more than 2 minutes old, or more than 60 s in the future. Check the client clock. |
| 10002 | IDENTIFY_INVALID_SIGNATURE | The signature did not verify against the public key. |
| 10003 | IDENTIFY_MISMATCH | A write, trim, delete or register-schema carries a client_id different from the one the connection proved with its RSA key. |
| 10004 | IDENTIFY_REQUIRED | The server runs with --require-client-identity and the first message was not Identify. The connection closes. |
| 10005 | AUTH_REQUIRED | The server has API keys configured and the Identify carried none. |
| 10006 | AUTH_INVALID_KEY | The API key is not valid base64, not 32 bytes, or matches no stored hash. |
| 10007 | AUTH_INSUFFICIENT_PERMISSIONS | A read-only API key attempted a write, trim, delete or register-schema. |
Server health (11xxx)
| Code | Name | Meaning |
|---|---|---|
| 11000 | SERVER_BUSY | The channel to the owning shard is full (--mesh-channel-size), so the request was not handed over. Back off and retry. Persistent 11000s mean an overloaded shard. |