Skip to content

docs: fix incorrect defaults, units, and unsupported option in connection string table#494

Merged
w1am merged 1 commit intomasterfrom
w1am/fix-default-deadline-doc
Apr 30, 2026
Merged

docs: fix incorrect defaults, units, and unsupported option in connection string table#494
w1am merged 1 commit intomasterfrom
w1am/fix-default-deadline-doc

Conversation

@w1am
Copy link
Copy Markdown
Collaborator

@w1am w1am commented Apr 30, 2026

Aligns the connection-string parameter table in docs/api/getting-started.md with the actual client code: corrects defaults for defaultDeadline / keepAliveInterval / keepAliveTimeout, switches gossipTimeout's documented unit to milliseconds, and removes the unimplemented tlsVerifyCert row.

Closes DEV-1648
Refs DEV-1649

@linear
Copy link
Copy Markdown

linear Bot commented Apr 30, 2026

@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Fix defaultDeadline default value documentation

📝 Documentation

Grey Divider

Walkthroughs

Description
• Fixed defaultDeadline default value in connection string table
• Changed documented default from None to 10000 milliseconds
• Aligns documentation with actual client constructor behavior
Diagram
flowchart LR
  A["Connection String Docs"] -->|incorrect default| B["None"]
  A -->|corrected to| C["10000 ms"]
  D["Client Constructor"] -->|actual default| C
Loading

Grey Divider

File Changes

1. docs/api/getting-started.md 📝 Documentation +1/-1

Update defaultDeadline default value to 10000

• Updated defaultDeadline parameter default value from None to 10000
• Corrects documentation to match actual client constructor implementation
• Maintains consistency with other numeric parameter defaults in the table

docs/api/getting-started.md


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Apr 30, 2026

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Remediation recommended

1. KeepAlive docs unit mismatch🐞 Bug ≡ Correctness
Description
The getting-started connection string table documents keepAliveInterval/keepAliveTimeout as seconds
(default 10), but the client passes these values directly to gRPC options
grpc.keepalive_time_ms/grpc.keepalive_timeout_ms (milliseconds) without any unit conversion.
Users who follow the docs (e.g., keepAliveInterval=10) will actually configure 10ms keep-alives,
causing excessive traffic and potential connection instability.
Code

docs/api/getting-started.md[R89-90]

| `keepAliveInterval`   | Number                                            | `10`     | Interval between keep-alive ping calls, in seconds.                                                                                            |
| `keepAliveTimeout`    | Number                                            | `10`     | Keep-alive ping call timeout, in seconds.                                                                                                      |
Evidence
The docs claim seconds, but connection-string parsing returns the raw integer and the channel
configuration consumes it as milliseconds via gRPC _ms settings, so the documented unit is
incorrect and leads to misconfiguration.

docs/api/getting-started.md[78-91]
packages/db-client/src/Client/parseConnectionString.ts[272-330]
packages/db-client/src/Client/index.ts[576-584]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`keepAliveInterval` and `keepAliveTimeout` are documented as seconds in `docs/api/getting-started.md`, but the implementation expects milliseconds (gRPC channel args use `_ms`) and the connection-string parser does not convert units.

### Issue Context
- `parseConnectionString` parses `keepAliveInterval`/`keepAliveTimeout` as integers and passes them through.
- `Client` uses these values in `grpc.keepalive_time_ms` and `grpc.keepalive_timeout_ms`.

### Fix Focus Areas
- docs/api/getting-started.md[78-91]
- packages/db-client/src/Client/index.ts[576-584]
- packages/db-client/src/Client/parseConnectionString.ts[317-330]

### Proposed change
Update the docs table rows to describe milliseconds (and update defaults accordingly, e.g. `10000`). If the intended public API is “seconds in connection string,” then instead implement conversion in parsing (multiply by 1000) and keep docs as-is—ensure docs and code match.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

2. Deadline constraint undocumented 🐞 Bug ⚙ Maintainability
Description
The docs table now lists defaultDeadline default as 10000, but it still doesn’t state that
defaultDeadline must be a positive integer and that <= 0 throws during client construction. This
can lead to surprising runtime errors for users setting defaultDeadline=0 or negative values via
connection string.
Code

docs/api/getting-started.md[88]

+| `defaultDeadline`     | Number                                            | `10000`  | Default timeout for client operations, in milliseconds. Most clients allow overriding the deadline per operation.                              |
Evidence
The client constructor enforces defaultDeadline > 0 by throwing, but the docs row does not mention
the constraint.

docs/api/getting-started.md[88-88]
packages/db-client/src/Client/index.ts[316-351]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Docs list `defaultDeadline` but don’t mention that the client rejects `defaultDeadline <= 0`.

### Issue Context
The constructor throws an error when `defaultDeadline <= 0`.

### Fix Focus Areas
- docs/api/getting-started.md[88-88]
- packages/db-client/src/Client/index.ts[347-351]

### Proposed change
Amend the `defaultDeadline` description to include that it must be a positive integer (ms) and that `0`/negative values are invalid.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@w1am w1am changed the title docs: fix defaultDeadline default value in connection string table docs: fix default values and units for timeout/keepAlive params Apr 30, 2026
@w1am w1am changed the title docs: fix default values and units for timeout/keepAlive params docs: fix incorrect defaults, units, and unsupported option in connection string table Apr 30, 2026
@qodo-code-review
Copy link
Copy Markdown

CI Feedback 🧐

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: Tests (ci) / persistentSubscription

Failed stage: Run Tests [❌]

Failed test name: subscribeToPersistentSubscriptionToStream › should connect to a persistent subscription › nack

Failure summary:

The GitHub Action failed because the Jest test run exited with code 1 after a failing test suite.
-
nx run test:test ./src/persistentSubscription --ci --run-in-band --forceExit reported 1 failed test
suite.
- Failed suite: src/persistentSubscription/subscribeToPersistentSubscriptionToStream.test.ts

- Failed test: subscribeToPersistentSubscriptionToStream › should connect to a persistent
subscription › nack
- As a result, Nx marked the test:test target as failed and the workflow ended
with ##[error]Process completed with exit code 1.

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

179:  �[94m➤�[39m �[90mYN0000�[39m: └ Completed in 4s 849ms
180:  �[94m➤�[39m �[90mYN0000�[39m: ┌ Post-resolution validation
181:  ##[group]Post-resolution validation
182:  �[93m➤�[39m YN0060: │ �[38;5;166m@opentelemetry/�[39m�[38;5;173mapi�[39m is listed by your project with version �[38;5;111m1.9.0�[39m (�[38;5;111mp28b0a�[39m), which doesn't satisfy what �[38;5;166m@opentelemetry/�[39m�[38;5;173mcore�[39m (via �[38;5;166m@opentelemetry/�[39m�[38;5;173mexporter-trace-otlp-grpc�[39m) and other dependencies request (�[38;5;37m>=1.4.0 <1.9.0�[39m).
183:  �[93m➤�[39m YN0002: │ �[38;5;173mtest�[39m�[38;5;111m@�[39m�[38;5;111mworkspace:packages/test�[39m doesn't provide �[38;5;173mtypescript�[39m (�[38;5;111mp6f314�[39m), requested by �[38;5;173mts-jest�[39m.
184:  �[93m➤�[39m YN0086: │ Some peer dependencies are incorrectly met by your project; run �[38;5;111myarn explain peer-requirements <hash>�[39m for details, where �[38;5;111m<hash>�[39m is the six-letter p-prefixed code.
185:  ##[endgroup]
186:  �[94m➤�[39m �[90mYN0000�[39m: └ Completed
187:  �[94m➤�[39m �[90mYN0000�[39m: ┌ Fetch step
188:  ##[group]Fetch step
189:  �[94m➤�[39m YN0013: │ �[38;5;220m1127�[39m packages were added to the project (�[38;5;160m+ 307.53 MiB�[39m).
190:  ##[endgroup]
191:  �[94m➤�[39m �[90mYN0000�[39m: └ Completed in 5s 150ms
192:  �[94m➤�[39m �[90mYN0000�[39m: ┌ Link step
193:  ##[group]Link step
194:  �[94m➤�[39m YN0007: │ �[38;5;173mnx�[39m�[38;5;111m@�[39m�[38;5;111mnpm:20.1.3 [7f914]�[39m must be built because it never has been before or the last one failed
195:  �[94m➤�[39m YN0007: │ �[38;5;173mprotobufjs�[39m�[38;5;111m@�[39m�[38;5;111mnpm:7.5.4�[39m must be built because it never has been before or the last one failed
196:  �[94m➤�[39m YN0007: │ �[38;5;173mgrpc-tools�[39m�[38;5;111m@�[39m�[38;5;111mnpm:1.13.1�[39m must be built because it never has been before or the last one failed
197:  �[94m➤�[39m YN0007: │ �[38;5;173mprotobufjs�[39m�[38;5;111m@�[39m�[38;5;111mnpm:7.4.0�[39m must be built because it never has been before or the last one failed
198:  �[94m➤�[39m YN0007: │ �[38;5;173mes5-ext�[39m�[38;5;111m@�[39m�[38;5;111mnpm:0.10.64�[39m must be built because it never has been before or the last one failed
199:  �[94m➤�[39m �[90mYN0000�[39m: │ �[38;5;173mgrpc-tools�[39m�[38;5;111m@�[39m�[38;5;111mnpm:1.13.1�[39m �[31mSTDERR�[39m [info] it worked if it ends with ok
200:  �[94m➤�[39m �[90mYN0000�[39m: │ �[38;5;173mgrpc-tools�[39m�[38;5;111m@�[39m�[38;5;111mnpm:1.13.1�[39m �[31mSTDERR�[39m [info] using node-pre-gyp@2.0.3
201:  �[94m➤�[39m �[90mYN0000�[39m: │ �[38;5;173mgrpc-tools�[39m�[38;5;111m@�[39m�[38;5;111mnpm:1.13.1�[39m �[31mSTDERR�[39m [info] using node@24.14.1 | linux | x64 
202:  �[94m➤�[39m �[90mYN0000�[39m: │ �[38;5;173mgrpc-tools�[39m�[38;5;111m@�[39m�[38;5;111mnpm:1.13.1�[39m �[31mSTDERR�[39m (node:2404) [DEP0169] DeprecationWarning: `url.parse()` behavior is not standardized and prone to errors that have security implications. Use the WHATWG URL API instead. CVEs are not issued for `url.parse()` vulnerabilities.
203:  �[94m➤�[39m �[90mYN0000�[39m: │ �[38;5;173mgrpc-tools�[39m�[38;5;111m@�[39m�[38;5;111mnpm:1.13.1�[39m �[31mSTDERR�[39m (Use `node --trace-deprecation ...` to show where the warning was created)
...

229:  //
230:  //     http://www.apache.org/licenses/LICENSE-2.0
231:  //
232:  // Unless required by applicable law or agreed to in writing, software
233:  // distributed under the License is distributed on an "AS IS" BASIS,
234:  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
235:  // See the License for the specific language governing permissions and
236:  // limitations under the License.
237:  syntax = "proto3";
238:  package google.rpc;
239:  option go_package = "google.golang.org/genproto/googleapis/rpc/code;code";
240:  option java_multiple_files = true;
241:  option java_outer_classname = "CodeProto";
242:  option java_package = "com.google.rpc";
243:  option objc_class_prefix = "RPC";
244:  // The canonical error codes for gRPC APIs.
245:  //
246:  //
247:  // Sometimes multiple error codes may apply.  Services should return
248:  // the most specific error code that applies.  For example, prefer
249:  // `OUT_OF_RANGE` over `FAILED_PRECONDITION` if both codes apply.
250:  // Similarly prefer `NOT_FOUND` or `ALREADY_EXISTS` over `FAILED_PRECONDITION`.
251:  enum Code {
252:  // Not an error; returned on success
253:  //
254:  // HTTP Mapping: 200 OK
255:  OK = 0;
256:  // The operation was cancelled, typically by the caller.
257:  //
258:  // HTTP Mapping: 499 Client Closed Request
259:  CANCELLED = 1;
260:  // Unknown error.  For example, this error may be returned when
261:  // a `Status` value received from another address space belongs to
262:  // an error space that is not known in this address space.  Also
263:  // errors raised by APIs that do not return enough error information
264:  // may be converted to this error.
265:  //
266:  // HTTP Mapping: 500 Internal Server Error
267:  UNKNOWN = 2;
268:  // The client specified an invalid argument.  Note that this differs
269:  // from `FAILED_PRECONDITION`.  `INVALID_ARGUMENT` indicates arguments
270:  // that are problematic regardless of the state of the system
271:  // (e.g., a malformed file name).
272:  //
273:  // HTTP Mapping: 400 Bad Request
274:  INVALID_ARGUMENT = 3;
275:  // The deadline expired before the operation could complete. For operations
276:  // that change the state of the system, this error may be returned
277:  // even if the operation has completed successfully.  For example, a
...

286:  // of users, such as gradual feature rollout or undocumented whitelist,
287:  // `NOT_FOUND` may be used. If a request is denied for some users within
288:  // a class of users, such as user-based access control, `PERMISSION_DENIED`
289:  // must be used.
290:  //
291:  // HTTP Mapping: 404 Not Found
292:  NOT_FOUND = 5;
293:  // The entity that a client attempted to create (e.g., file or directory)
294:  // already exists.
295:  //
296:  // HTTP Mapping: 409 Conflict
297:  ALREADY_EXISTS = 6;
298:  // The caller does not have permission to execute the specified
299:  // operation. `PERMISSION_DENIED` must not be used for rejections
300:  // caused by exhausting some resource (use `RESOURCE_EXHAUSTED`
301:  // instead for those errors). `PERMISSION_DENIED` must not be
302:  // used if the caller can not be identified (use `UNAUTHENTICATED`
303:  // instead for those errors). This error code does not imply the
304:  // request is valid or the requested entity exists or satisfies
...

310:  // operation.
311:  //
312:  // HTTP Mapping: 401 Unauthorized
313:  UNAUTHENTICATED = 16;
314:  // Some resource has been exhausted, perhaps a per-user quota, or
315:  // perhaps the entire file system is out of space.
316:  //
317:  // HTTP Mapping: 429 Too Many Requests
318:  RESOURCE_EXHAUSTED = 8;
319:  // The operation was rejected because the system is not in a state
320:  // required for the operation's execution.  For example, the directory
321:  // to be deleted is non-empty, an rmdir operation is applied to
322:  // a non-directory, etc.
323:  //
324:  // Service implementors can use the following guidelines to decide
325:  // between `FAILED_PRECONDITION`, `ABORTED`, and `UNAVAILABLE`:
326:  //  (a) Use `UNAVAILABLE` if the client can retry just the failing call.
327:  //  (b) Use `ABORTED` if the client should retry at a higher level
328:  //      (e.g., when a client-specified test-and-set fails, indicating the
329:  //      client should restart a read-modify-write sequence).
330:  //  (c) Use `FAILED_PRECONDITION` if the client should not retry until
331:  //      the system state has been explicitly fixed.  E.g., if an "rmdir"
332:  //      fails because the directory is non-empty, `FAILED_PRECONDITION`
333:  //      should be returned since the client should not retry unless
334:  //      the files are deleted from the directory.
335:  //
336:  // HTTP Mapping: 400 Bad Request
337:  FAILED_PRECONDITION = 9;
338:  // The operation was aborted, typically due to a concurrency issue such as
339:  // a sequencer check failure or transaction abort.
340:  //
341:  // See the guidelines above for deciding between `FAILED_PRECONDITION`,
342:  // `ABORTED`, and `UNAVAILABLE`.
343:  //
344:  // HTTP Mapping: 409 Conflict
345:  ABORTED = 10;
346:  // The operation was attempted past the valid range.  E.g., seeking or
347:  // reading past end-of-file.
348:  //
349:  // Unlike `INVALID_ARGUMENT`, this error indicates a problem that may
350:  // be fixed if the system state changes. For example, a 32-bit file
351:  // system will generate `INVALID_ARGUMENT` if asked to read at an
352:  // offset that is not in the range [0,2^32-1], but it will generate
353:  // `OUT_OF_RANGE` if asked to read from an offset past the current
354:  // file size.
355:  //
356:  // There is a fair bit of overlap between `FAILED_PRECONDITION` and
357:  // `OUT_OF_RANGE`.  We recommend using `OUT_OF_RANGE` (the more specific
358:  // error) when it applies so that callers who are iterating through
359:  // a space can easily look for an `OUT_OF_RANGE` error to detect when
360:  // they are done.
361:  //
362:  // HTTP Mapping: 400 Bad Request
363:  OUT_OF_RANGE = 11;
364:  // The operation is not implemented or is not supported/enabled in this
365:  // service.
366:  //
367:  // HTTP Mapping: 501 Not Implemented
368:  UNIMPLEMENTED = 12;
369:  // Internal errors.  This means that some invariants expected by the
370:  // underlying system have been broken.  This error code is reserved
371:  // for serious errors.
372:  //
373:  // HTTP Mapping: 500 Internal Server Error
374:  INTERNAL = 13;
375:  // The service is currently unavailable.  This is most likely a
376:  // transient condition, which can be corrected by retrying with
377:  // a backoff. Note that it is not always safe to retry
378:  // non-idempotent operations.
379:  //
380:  // See the guidelines above for deciding between `FAILED_PRECONDITION`,
381:  // `ABORTED`, and `UNAVAILABLE`.
382:  //
383:  // HTTP Mapping: 503 Service Unavailable
384:  UNAVAILABLE = 14;
385:  // Unrecoverable data loss or corruption.
386:  //
387:  // HTTP Mapping: 500 Internal Server Error
388:  DATA_LOSS = 15;
...

1014:  // Unless required by applicable law or agreed to in writing, software
1015:  // distributed under the License is distributed on an "AS IS" BASIS,
1016:  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1017:  // See the License for the specific language governing permissions and
1018:  // limitations under the License.
1019:  syntax = "proto3";
1020:  package google.rpc;
1021:  import "google/protobuf/any.proto";
1022:  import "kurrentdb/protocols/v1/code.proto";
1023:  option cc_enable_arenas = true;
1024:  option go_package = "google.golang.org/genproto/googleapis/rpc/status;status";
1025:  option java_multiple_files = true;
1026:  option java_outer_classname = "StatusProto";
1027:  option java_package = "com.google.rpc";
1028:  option objc_class_prefix = "RPC";
1029:  // The `Status` type defines a logical error model that is suitable for
1030:  // different programming environments, including REST APIs and RPC APIs. It is
1031:  // used by [gRPC](https://github.com/grpc). Each `Status` message contains
1032:  // three pieces of data: error code, error message, and error details.
1033:  //
1034:  // You can find out more about this error model and how to work with it in the
1035:  // [API Design Guide](https://cloud.google.com/apis/design/errors).
1036:  message Status {
1037:  // The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code].
1038:  google.rpc.Code code = 1;
1039:  // A developer-facing error message, which should be in English. Any
1040:  // user-facing error message should be localized and sent in the
1041:  // [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client.
1042:  string message = 2;
1043:  // A list of messages that carry the error details.  There is a common set of
1044:  // message types for APIs to use.
...

1280:  oneof deadline_option {
1281:  google.protobuf.Timestamp deadline_21_10_0 = 6;
1282:  google.protobuf.Duration deadline = 7;
1283:  }
1284:  }
1285:  message ProposedMessage {
1286:  event_store.client.UUID id = 1;
1287:  map<string, string> metadata = 2;
1288:  bytes custom_metadata = 3;
1289:  bytes data = 4;
1290:  }
1291:  }
1292:  message BatchAppendResp {
1293:  event_store.client.UUID correlation_id = 1;
1294:  oneof result {
1295:  google.rpc.Status error = 2;
1296:  Success success = 3;
...

1447:  }
1448:  message ResetPasswordReq {
1449:  Options options = 1;
1450:  message Options {
1451:  string login_name = 1;
1452:  string new_password = 2;
1453:  }
1454:  }
1455:  message ResetPasswordResp {
1456:  }
1457:  // ******************************************************************************************
1458:  // This protocol is UNSTABLE in the sense of being subject to change.
1459:  // ******************************************************************************************
1460:  syntax = "proto3";
1461:  package kurrent.rpc;
1462:  option csharp_namespace = "KurrentDB.Protocol.V2.Common.Errors";
1463:  import "kurrentdb/protocols/v2/rpc.proto";
1464:  // The canonical server error codes for the Kurrent Platform gRPC APIs.
1465:  // These errors represent common failure modes across all Kurrent services.
1466:  enum ServerError {
1467:  // Default value. This value is not used.
1468:  // An error code MUST always be set to a non-zero value.
1469:  // If an error code is not explicitly set, it MUST be treated as
1470:  // an internal server error (INTERNAL).
1471:  UNSPECIFIED = 0;
1472:  // Authentication or authorization failure.
1473:  // The client lacks valid credentials or sufficient permissions to perform the requested operation.
1474:  //
1475:  // Common causes:
1476:  // - Missing or invalid authentication tokens
1477:  // - Insufficient permissions for the operation
1478:  // - Expired credentials
1479:  //
1480:  // Client action: Check credentials, verify permissions, and re-authenticate if necessary.
1481:  // Not retriable without fixing the underlying authorization issue.
1482:  SERVER_ERROR_ACCESS_DENIED = 1 [(kurrent.rpc.error) = {
1483:  status_code: PERMISSION_DENIED,
1484:  has_details: true
1485:  }];
1486:  // The request is malformed or contains invalid data.
1487:  // The server cannot process the request due to client error.
1488:  //
1489:  // Common causes:
1490:  // - Invalid field values (e.g., empty required fields, out-of-range numbers)
1491:  // - Malformed data formats
1492:  // - Validation failures
1493:  //
1494:  // Client action: Fix the request data and retry.
1495:  // Not retriable without modifying the request.
1496:  SERVER_ERROR_BAD_REQUEST = 2 [(kurrent.rpc.error) = {
1497:  status_code: INVALID_ARGUMENT,
1498:  has_details: true
1499:  }];
1500:  // The server is not the cluster leader and cannot process write operations.
1501:  // In a clustered deployment, only the leader node can accept write operations.
1502:  //
1503:  // Common causes:
1504:  // - Client connected to a follower node
1505:  // - Leader election in progress
1506:  // - Network partition
1507:  //
1508:  // Client action: Redirect the request to the leader node indicated in the error details.
1509:  // Retriable after redirecting to the correct leader node.
1510:  SERVER_ERROR_NOT_LEADER_NODE = 5 [(kurrent.rpc.error) = {
1511:  status_code: FAILED_PRECONDITION,
1512:  has_details: true
1513:  }];
1514:  // The operation did not complete within the configured timeout period.
1515:  //
1516:  // Common causes:
1517:  // - Slow disk I/O during writes
1518:  // - Cluster consensus delays
1519:  // - Network latency
1520:  // - Heavy server load
1521:  //
1522:  // Client action: Retry with exponential backoff. Consider increasing timeout values.
1523:  // Retriable - the operation may succeed on retry.
1524:  SERVER_ERROR_OPERATION_TIMEOUT = 6 [(kurrent.rpc.error) = {
1525:  status_code: DEADLINE_EXCEEDED
1526:  }];
1527:  // The server is starting up or shutting down and cannot process requests.
1528:  //
1529:  // Common causes:
1530:  // - Server is initializing (loading indexes, recovering state)
1531:  // - Server is performing graceful shutdown
1532:  // - Server is performing maintenance operations
1533:  //
1534:  // Client action: Retry with exponential backoff. Wait for server to become ready.
1535:  // Retriable - the server will become available after initialization completes.
1536:  SERVER_ERROR_SERVER_NOT_READY = 7 [(kurrent.rpc.error) = {
1537:  status_code: UNAVAILABLE
1538:  }];
1539:  // The server is temporarily overloaded and cannot accept more requests.
1540:  // This is a backpressure mechanism to prevent server overload.
1541:  //
1542:  // Common causes:
1543:  // - Too many concurrent requests
1544:  // - Resource exhaustion (CPU, memory, disk I/O)
1545:  // - Rate limiting triggered
1546:  //
1547:  // Client action: Retry with exponential backoff. Reduce request rate.
1548:  // Retriable - the server may accept requests after load decreases.
1549:  SERVER_ERROR_SERVER_OVERLOADED = 8 [(kurrent.rpc.error) = {
1550:  status_code: UNAVAILABLE
1551:  }];
1552:  // An internal server error occurred.
1553:  // This indicates a bug or unexpected condition in the server.
1554:  //
1555:  // Common causes:
1556:  // - Unhandled exceptions
1557:  // - Assertion failures
1558:  // - Corrupted internal state
1559:  // - Programming errors
1560:  //
1561:  // Client action: Report to server administrators with request details.
1562:  // May be retriable, but likely indicates a server-side issue requiring investigation.
1563:  SERVER_ERROR_SERVER_MALFUNCTION = 9 [(kurrent.rpc.error) = {
1564:  status_code: INTERNAL
1565:  }];
1566:  }
1567:  // Details for ACCESS_DENIED errors.
1568:  message AccessDeniedErrorDetails {
1569:  // The friendly name of the operation that was denied.
1570:  string operation = 1;
1571:  // The username of the user who was denied access.
1572:  optional string username = 2;
1573:  // The permission that was required for this operation.
1574:  optional string permission = 3;
1575:  }
1576:  // Details for NOT_LEADER_NODE errors.
1577:  message NotLeaderNodeErrorDetails {
1578:  // Information about the current cluster leader node.
...

1583:  string host = 1;
1584:  // The gRPC port of the node.
1585:  int32 port = 2;
1586:  // The unique instance ID of the node.
1587:  optional string node_id = 3;
1588:  }
1589:  }
1590:  // ******************************************************************************************
1591:  // This protocol is UNSTABLE in the sense of being subject to change.
1592:  // ******************************************************************************************
1593:  syntax = "proto3";
1594:  package kurrent.rpc;
1595:  option csharp_namespace = "Kurrent.Rpc";
1596:  import "google/protobuf/descriptor.proto";
1597:  import "kurrentdb/protocols/v1/code.proto";
1598:  // ErrorMetadata provides actionable information for error enum values to enable automated
1599:  // code generation, documentation, and consistent error handling across the Kurrent platform.
1600:  //
1601:  // It was modeled to support a single details type per error code to simplify code generation and
1602:  // validation. If multiple detail types are needed for a single error code, consider defining
1603:  // separate error codes for each detail type. Or, use a union type (oneof) in the detail message
1604:  // to encapsulate multiple detail variants within a single detail message.
1605:  //
1606:  // More however DebugInfo and RetryInfo can and should be added to any error regardless of
1607:  // this setting, when applicable.
1608:  //
1609:  // This annotation is applied to enum values using the google.protobuf.EnumValueOptions
1610:  // extension mechanism. It enables:
1611:  // - Automatic gRPC status code mapping
1612:  // - Code generation for error handling utilities
1613:  // - Documentation generation
1614:  // - Type-safe error detail validation
1615:  //
1616:  // Usage Example:
1617:  //   enum StreamErrorCode {
1618:  //     REVISION_CONFLICT = 5 [(kurrent.rpc.error) = {
1619:  //       status_code: FAILED_PRECONDITION,
1620:  //       has_details: true
1621:  //     }];
1622:  //   }
1623:  //
1624:  // See individual field documentation for conventions and defaults.
1625:  message ErrorMetadata {
1626:  // Maps the error to a standard gRPC status code for transport-level compatibility.
1627:  // This field is REQUIRED for every error annotation.
1628:  //
1629:  // Use standard gRPC status codes from `google.rpc.code`.
1630:  //
1631:  // Code generators use this to:
1632:  // - Map errors to gRPC status codes automatically
1633:  // - Generate HTTP status code mappings
1634:  // - Create transport-agnostic error handling
1635:  google.rpc.Code status_code = 1;
1636:  // Indicates whether this error supports rich, typed detail messages.
1637:  // Defaults to false (simple message string only).
1638:  // The message type name must be derived from the enum name by convention.
1639:  // Mask: {EnumValue}ErrorDetails, {EnumValue}Error, {EnumValue}
1640:  //
1641:  // Examples:
1642:  //   ACCESS_DENIED    -> "AccessDeniedErrorDetails", "AccessDeniedError" or "AccessDenied"
1643:  //   SERVER_NOT_READY -> "ServerNotReadyErrorDetails", "ServerNotReadyError" or "ServerNotReady"
1644:  //
1645:  // Code generators use the message type name to:
1646:  // - Validate that the detail message matches the expected type
1647:  // - Generate type-safe error handling code
1648:  // - Create accurate documentation
1649:  bool has_details = 2;
1650:  }
1651:  // Extend EnumValueOptions to include error information for enum values
1652:  extend google.protobuf.EnumValueOptions {
1653:  // Provides additional information about error conditions for automated
1654:  // code generation and documentation.
1655:  optional ErrorMetadata error = 50000;
1656:  }
1657:  // ******************************************************************************************
1658:  // This protocol is UNSTABLE in the sense of being subject to change.
1659:  // ******************************************************************************************
1660:  syntax = "proto3";
1661:  package kurrentdb.protocol.v2.streams.errors;
1662:  option csharp_namespace = "KurrentDB.Protocol.V2.Streams.Errors";
1663:  import "kurrentdb/protocols/v2/rpc.proto";
1664:  // Error codes specific to the Streams API.
1665:  // These errors represent failure modes when working with streams of records.
1666:  enum StreamsError {
1667:  // Default value. This value is not used.
1668:  // An error code MUST always be set to a non-zero value.
1669:  // If an error code is not explicitly set, it MUST be treated as
1670:  // an internal server error (INTERNAL).
1671:  STREAMS_ERROR_UNSPECIFIED = 0;
1672:  // The requested stream does not exist in the database.
1673:  //
1674:  // Common causes:
1675:  // - Stream name typo or incorrect stream identifier
1676:  // - Stream was never created (no events appended yet)
1677:  // - Stream was deleted and not yet recreated
1678:  //
1679:  // Client action: Verify the stream name is correct. Create the stream by appending to it.
1680:  // Recoverable by creating the stream first (append with NO_STREAM expected revision).
1681:  STREAMS_ERROR_STREAM_NOT_FOUND = 1 [(kurrent.rpc.error) = {
1682:  status_code: NOT_FOUND,
1683:  has_details: true,
1684:  }];
1685:  // The stream already exists when an operation expected it not to exist.
1686:  //
1687:  // Common causes:
1688:  // - Attempting to create a stream that already has events
1689:  // - Using NO_STREAM expected revision on an existing stream
1690:  // - Race condition with concurrent stream creation
1691:  //
1692:  // Client action: Use the existing stream or use a different expected revision.
1693:  // Recoverable by adjusting the expected revision or using the existing stream.
1694:  STREAMS_ERROR_STREAM_ALREADY_EXISTS = 2 [(kurrent.rpc.error) = {
1695:  status_code: ALREADY_EXISTS,
1696:  has_details: true
1697:  }];
1698:  // The stream has been soft deleted.
1699:  // Soft-deleted streams are hidden from stream lists but can be restored by appending to them.
1700:  //
1701:  // Common causes:
1702:  // - Stream was explicitly soft-deleted via delete operation
1703:  // - Attempting to read from a soft-deleted stream
1704:  //
1705:  // Client action: Restore the stream by appending new events, or accept that the stream is deleted.
1706:  // Recoverable by appending to the stream to restore it.
1707:  STREAMS_ERROR_STREAM_DELETED = 3 [(kurrent.rpc.error) = {
1708:  status_code: FAILED_PRECONDITION,
1709:  has_details: true
1710:  }];
1711:  // The stream has been tombstoned (permanently deleted).
1712:  // Tombstoned streams cannot be restored and will never accept new events.
1713:  //
1714:  // Common causes:
1715:  // - Stream was explicitly tombstoned via tombstone operation
1716:  // - Administrative deletion of sensitive data
1717:  // - Attempting to write to or read from a tombstoned stream
1718:  //
1719:  // Client action: Stream is permanently removed. Create a new stream with a different name if needed.
1720:  // Not recoverable - the stream cannot be restored.
1721:  STREAMS_ERROR_STREAM_TOMBSTONED = 4 [(kurrent.rpc.error) = {
1722:  status_code: FAILED_PRECONDITION,
1723:  has_details: true
1724:  }];
1725:  // The expected revision does not match the actual stream revision.
1726:  // This is an optimistic concurrency control failure.
1727:  //
1728:  // Common causes:
1729:  // - Another client modified the stream concurrently
1730:  // - Client has stale state about the stream revision
1731:  // - Race condition in distributed system
1732:  //
1733:  // Client action: Fetch the current stream revision and retry with the correct expected revision.
1734:  // Recoverable by reading the current state and retrying with proper optimistic concurrency control.
1735:  STREAMS_ERROR_STREAM_REVISION_CONFLICT = 5 [(kurrent.rpc.error) = {
1736:  status_code: FAILED_PRECONDITION,
1737:  has_details: true
1738:  }];
1739:  // A single record being appended exceeds the maximum allowed size.
1740:  //
1741:  // Common causes:
1742:  // - Record payload is too large (exceeds server's max record size configuration)
1743:  // - Excessive metadata in properties
1744:  // - Large binary data without chunking
1745:  //
1746:  // Client action: Reduce record size, split large payloads across multiple records, or increase server limits.
1747:  // Recoverable by reducing record size or adjusting server configuration.
1748:  STREAMS_ERROR_APPEND_RECORD_SIZE_EXCEEDED = 6 [(kurrent.rpc.error) = {
1749:  status_code: INVALID_ARGUMENT,
1750:  has_details: true
1751:  }];
1752:  // The total size of all records in a single append session exceeds the maximum allowed transaction size.
1753:  //
1754:  // Common causes:
1755:  // - Too many records in a single append session
1756:  // - Combined payload size exceeds server's max transaction size
1757:  // - Attempting to write very large batches
1758:  //
1759:  // Client action: Split the append into multiple smaller transactions.
1760:  // Recoverable by reducing the number of records per append session.
1761:  STREAMS_ERROR_APPEND_TRANSACTION_SIZE_EXCEEDED = 7 [(kurrent.rpc.error) = {
1762:  status_code: ABORTED,
1763:  has_details: true
1764:  }];
1765:  // The same stream appears multiple times in a single append session.
1766:  // This is currently not supported to prevent complexity with expected revisions and ordering.
1767:  //
1768:  // Common causes:
1769:  // - Accidentally appending to the same stream twice in one session
1770:  // - Application logic error in batch operations
1771:  //
1772:  // Client action: Remove duplicate streams from the append session or split into multiple sessions.
1773:  // Recoverable by restructuring the append session to reference each stream only once.
1774:  STREAMS_ERROR_STREAM_ALREADY_IN_APPEND_SESSION = 8 [(kurrent.rpc.error) = {
1775:  status_code: ABORTED,
1776:  has_details: true
1777:  }];
1778:  // An append session was started but no append requests were sent before completing the stream.
1779:  //
1780:  // Common causes:
1781:  // - Client completed the stream without sending any AppendRequest messages
1782:  // - Application logic error
1783:  //
1784:  // Client action: Ensure at least one AppendRequest is sent before completing the stream.
1785:  // Recoverable by properly implementing the append session protocol.
1786:  STREAMS_ERROR_APPEND_SESSION_NO_REQUESTS = 9 [(kurrent.rpc.error) = {
1787:  status_code: FAILED_PRECONDITION
1788:  }];
1789:  // One or more consistency checks failed during an AppendRecords operation.
1790:  // The transaction is aborted — no records are written.
1791:  //
1792:  // Common causes:
1793:  // - A stream state check found the stream at a different revision than expected
1794:  // - A stream referenced in a state check does not exist, was deleted, or was tombstoned
1795:  //
1796:  // Client action: Inspect the AppendConsistencyViolationErrorDetails to determine which
1797:  // checks failed and why, then correct the request or refresh local state and retry.
1798:  // Recoverable by reading the current state and resubmitting with updated checks.
1799:  STREAMS_ERROR_APPEND_CONSISTENCY_VIOLATION = 14 [(kurrent.rpc.error) = {
1800:  status_code: FAILED_PRECONDITION,
1801:  has_details: true
1802:  }];
1803:  }
1804:  // Details for STREAM_NOT_FOUND errors.
1805:  message StreamNotFoundErrorDetails {
1806:  // The name of the stream that was not found.
1807:  string stream = 1;
1808:  }
1809:  // Details for STREAM_ALREADY_EXISTS errors.
1810:  message StreamAlreadyExistsErrorDetails {
1811:  // The name of the stream that already exists.
1812:  string stream = 1;
1813:  }
1814:  // Details for STREAM_DELETED errors.
1815:  message StreamDeletedErrorDetails {
1816:  // The name of the stream that was deleted.
1817:  string stream = 1;
1818:  }
1819:  // Details for STREAM_TOMBSTONED errors.
1820:  message StreamTombstonedErrorDetails {
1821:  // The name of the stream that was tombstoned.
1822:  string stream = 1;
1823:  }
1824:  // Details for STREAM_REVISION_CONFLICT errors.
1825:  message StreamRevisionConflictErrorDetails {
1826:  // The name of the stream that had a revision conflict.
1827:  string stream = 1;
1828:  // The expected revision that was provided in the append request.
1829:  sint64 expected_revision = 2 [jstype = JS_STRING];
1830:  // The actual current revision of the stream.
1831:  sint64 actual_revision = 3 [jstype = JS_STRING];
1832:  }
1833:  // Details for APPEND_RECORD_SIZE_EXCEEDED errors.
1834:  message AppendRecordSizeExceededErrorDetails {
1835:  // The name of the stream where the append was attempted.
1836:  string stream = 1;
1837:  // The identifier of the record that exceeded the size limit.
1838:  string record_id = 2;
1839:  // The actual size of the record in bytes.
1840:  int32 size = 3;
1841:  // The maximum allowed size of a single record in bytes.
1842:  int32 max_size = 4;
1843:  }
1844:  // Details for APPEND_TRANSACTION_SIZE_EXCEEDED errors.
1845:  message AppendTransactionSizeExceededErrorDetails {
1846:  // The actual size of the transaction in bytes.
1847:  int32 size = 1;
1848:  // The maximum allowed size of an append transaction in bytes.
1849:  int32 max_size = 2;
1850:  }
1851:  // Details for STREAM_ALREADY_IN_APPEND_SESSION errors.
1852:  message StreamAlreadyInAppendSessionErrorDetails {
1853:  // The name of the stream that appears multiple times.
1854:  string stream = 1;
1855:  }
1856:  // Details for APPEND_CONSISTENCY_VIOLATION errors.
1857:  //
1858:  // Contains all consistency checks that were violated during the append operation.
1859:  // Only violated checks are included; satisfied checks are omitted.
1860:  message AppendConsistencyViolationErrorDetails {
1861:  // The consistency checks that were violated.
...

1881:  }
1882:  // ******************************************************************************************
1883:  // This protocol is UNSTABLE in the sense of being subject to change.
1884:  // ******************************************************************************************
1885:  syntax = "proto3";
1886:  package kurrentdb.protocol.v2.streams;
1887:  option csharp_namespace = "KurrentDB.Protocol.V2.Streams";
1888:  import "google/protobuf/struct.proto";
1889:  service StreamsService {
1890:  // Appends records to multiple streams atomically within a single transaction.
1891:  //
1892:  // This is a client-streaming RPC where the client sends multiple AppendRequest messages
1893:  // (one per stream) and receives a single AppendSessionResponse upon commit.
1894:  //
1895:  // Guarantees:
1896:  // - Atomicity: All writes succeed or all fail together
1897:  // - Optimistic Concurrency: Expected revisions are validated for all streams before commit
...

1909:  rpc AppendSession(stream AppendRequest) returns (AppendSessionResponse);
1910:  // Appends records to multiple streams atomically with cross-stream consistency checks.
1911:  //
1912:  // This is a unary RPC where the client sends all records and consistency checks
1913:  // in a single request and receives a single AppendRecordsResponse.
1914:  //
1915:  // Records can be interleaved across streams in any order and the global log preserves
1916:  // the exact sequence from the request.
1917:  //
1918:  // Consistency checks are decoupled from writes: a check can reference any stream,
1919:  // whether or not the request writes to it. This enables Dynamic Consistency Boundary
1920:  // (DCB) patterns where a decision depends on multiple streams but only produces
1921:  // events for a subset.
1922:  //
1923:  // Guarantees:
1924:  // - Atomicity: All writes succeed or all fail together
1925:  // - Ordering: Records maintain the exact send order in the global log
1926:  // - Cross-stream checks: Consistency checks can reference any stream
1927:  //
1928:  // On consistency check failure, no records are written and all failing checks
1929:  // are reported in the response so the client can refresh stale state in one round trip.
...

2013:  // The record payload as raw bytes.
2014:  // The format specified in SchemaInfo determines how to interpret these bytes.
2015:  bytes data = 4;
2016:  // Target stream for this record.
2017:  // Required for AppendRecords (each record specifies its own stream).
2018:  // Ignored for AppendSession (the stream is specified in AppendRequest).
2019:  string stream = 5;
2020:  }
2021:  // Constants for expected revision validation in optimistic concurrency control.
2022:  // These can be used in the expected_revision field, or you can specify an actual revision number.
2023:  enum ExpectedRevisionConstants {
2024:  // The stream must have exactly one event at revision 0.
2025:  // Used for scenarios requiring strict single-event semantics.
2026:  EXPECTED_REVISION_CONSTANTS_SINGLE_EVENT = 0;
2027:  // The stream must not exist yet (first write to the stream).
2028:  // Fails if the stream already has events.
2029:  EXPECTED_REVISION_CONSTANTS_NO_STREAM = -1;
2030:  // Accept any current state of the stream (no optimistic concurrency check).
2031:  // The write will succeed regardless of the stream's current revision.
2032:  EXPECTED_REVISION_CONSTANTS_ANY = -2;
2033:  // The stream must exist (have at least one record).
2034:  // Fails if the stream doesn't exist yet.
2035:  EXPECTED_REVISION_CONSTANTS_EXISTS = -4;
2036:  }
2037:  // Request to append records to one or more streams atomically.
2038:  //
2039:  // All records are committed in a single transaction. Each record specifies its
2040:  // target stream via AppendRecord.stream. Consistency checks are evaluated before
2041:  // any records are written.
2042:  message AppendRecordsRequest {
2043:  // The records to append. Records targeting the same stream maintain their
2044:  // order from this list.
2045:  repeated AppendRecord records = 1;
2046:  // Optional consistency checks evaluated before commit. If any check fails,
2047:  // the entire transaction is aborted.
...

2090:  //
2091:  //     http://www.apache.org/licenses/LICENSE-2.0
2092:  //
2093:  // Unless required by applicable law or agreed to in writing, software
2094:  // distributed under the License is distributed on an "AS IS" BASIS,
2095:  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2096:  // See the License for the specific language governing permissions and
2097:  // limitations under the License.
2098:  syntax = "proto3";
2099:  package google.rpc;
2100:  option go_package = "google.golang.org/genproto/googleapis/rpc/code;code";
2101:  option java_multiple_files = true;
2102:  option java_outer_classname = "CodeProto";
2103:  option java_package = "com.google.rpc";
2104:  option objc_class_prefix = "RPC";
2105:  // The canonical error codes for gRPC APIs.
2106:  //
2107:  //
2108:  // Sometimes multiple error codes may apply.  Services should return
2109:  // the most specific error code that applies.  For example, prefer
2110:  // `OUT_OF_RANGE` over `FAILED_PRECONDITION` if both codes apply.
2111:  // Similarly prefer `NOT_FOUND` or `ALREADY_EXISTS` over `FAILED_PRECONDITION`.
2112:  enum Code {
2113:  // Not an error; returned on success
2114:  //
2115:  // HTTP Mapping: 200 OK
2116:  OK = 0;
2117:  // The operation was cancelled, typically by the caller.
2118:  //
2119:  // HTTP Mapping: 499 Client Closed Request
2120:  CANCELLED = 1;
2121:  // Unknown error.  For example, this error may be returned when
2122:  // a `Status` value received from another address space belongs to
2123:  // an error space that is not known in this address space.  Also
2124:  // errors raised by APIs that do not return enough error information
2125:  // may be converted to this error.
2126:  //
2127:  // HTTP Mapping: 500 Internal Server Error
2128:  UNKNOWN = 2;
2129:  // The client specified an invalid argument.  Note that this differs
2130:  // from `FAILED_PRECONDITION`.  `INVALID_ARGUMENT` indicates arguments
2131:  // that are problematic regardless of the state of the system
2132:  // (e.g., a malformed file name).
2133:  //
2134:  // HTTP Mapping: 400 Bad Request
2135:  INVALID_ARGUMENT = 3;
2136:  // The deadline expired before the operation could complete. For operations
2137:  // that change the state of the system, this error may be returned
2138:  // even if the operation has completed successfully.  For example, a
...

2147:  // of users, such as gradual feature rollout or undocumented whitelist,
2148:  // `NOT_FOUND` may be used. If a request is denied for some users within
2149:  // a class of users, such as user-based access control, `PERMISSION_DENIED`
2150:  // must be used.
2151:  //
2152:  // HTTP Mapping: 404 Not Found
2153:  NOT_FOUND = 5;
2154:  // The entity that a client attempted to create (e.g., file or directory)
2155:  // already exists.
2156:  //
2157:  // HTTP Mapping: 409 Conflict
2158:  ALREADY_EXISTS = 6;
2159:  // The caller does not have permission to execute the specified
2160:  // operation. `PERMISSION_DENIED` must not be used for rejections
2161:  // caused by exhausting some resource (use `RESOURCE_EXHAUSTED`
2162:  // instead for those errors). `PERMISSION_DENIED` must not be
2163:  // used if the caller can not be identified (use `UNAUTHENTICATED`
2164:  // instead for those errors). This error code does not imply the
2165:  // request is valid or the requested entity exists or satisfies
...

2171:  // operation.
2172:  //
2173:  // HTTP Mapping: 401 Unauthorized
2174:  UNAUTHENTICATED = 16;
2175:  // Some resource has been exhausted, perhaps a per-user quota, or
2176:  // perhaps the entire file system is out of space.
2177:  //
2178:  // HTTP Mapping: 429 Too Many Requests
2179:  RESOURCE_EXHAUSTED = 8;
2180:  // The operation was rejected because the system is not in a state
2181:  // required for the operation's execution.  For example, the directory
2182:  // to be deleted is non-empty, an rmdir operation is applied to
2183:  // a non-directory, etc.
2184:  //
2185:  // Service implementors can use the following guidelines to decide
2186:  // between `FAILED_PRECONDITION`, `ABORTED`, and `UNAVAILABLE`:
2187:  //  (a) Use `UNAVAILABLE` if the client can retry just the failing call.
2188:  //  (b) Use `ABORTED` if the client should retry at a higher level
2189:  //      (e.g., when a client-specified test-and-set fails, indicating the
2190:  //      client should restart a read-modify-write sequence).
2191:  //  (c) Use `FAILED_PRECONDITION` if the client should not retry until
2192:  //      the system state has been explicitly fixed.  E.g., if an "rmdir"
2193:  //      fails because the directory is non-empty, `FAILED_PRECONDITION`
2194:  //      should be returned since the client should not retry unless
2195:  //      the files are deleted from the directory.
2196:  //
2197:  // HTTP Mapping: 400 Bad Request
2198:  FAILED_PRECONDITION = 9;
2199:  // The operation was aborted, typically due to a concurrency issue such as
2200:  // a sequencer check failure or transaction abort.
2201:  //
2202:  // See the guidelines above for deciding between `FAILED_PRECONDITION`,
2203:  // `ABORTED`, and `UNAVAILABLE`.
2204:  //
2205:  // HTTP Mapping: 409 Conflict
2206:  ABORTED = 10;
2207:  // The operation was attempted past the valid range.  E.g., seeking or
2208:  // reading past end-of-file.
2209:  //
2210:  // Unlike `INVALID_ARGUMENT`, this error indicates a problem that may
2211:  // be fixed if the system state changes. For example, a 32-bit file
2212:  // system will generate `INVALID_ARGUMENT` if asked to read at an
2213:  // offset that is not in the range [0,2^32-1], but it will generate
2214:  // `OUT_OF_RANGE` if asked to read from an offset past the current
2215:  // file size.
2216:  //
2217:  // There is a fair bit of overlap between `FAILED_PRECONDITION` and
2218:  // `OUT_OF_RANGE`.  We recommend using `OUT_OF_RANGE` (the more specific
2219:  // error) when it applies so that callers who are iterating through
2220:  // a space can easily look for an `OUT_OF_RANGE` error to detect when
2221:  // they are done.
2222:  //
2223:  // HTTP Mapping: 400 Bad Request
2224:  OUT_OF_RANGE = 11;
2225:  // The operation is not implemented or is not supported/enabled in this
2226:  // service.
2227:  //
2228:  // HTTP Mapping: 501 Not Implemented
2229:  UNIMPLEMENTED = 12;
2230:  // Internal errors.  This means that some invariants expected by the
2231:  // underlying system have been broken.  This error code is reserved
2232:  // for serious errors.
2233:  //
2234:  // HTTP Mapping: 500 Internal Server Error
2235:  INTERNAL = 13;
2236:  // The service is currently unavailable.  This is most likely a
2237:  // transient condition, which can be corrected by retrying with
2238:  // a backoff. Note that it is not always safe to retry
2239:  // non-idempotent operations.
2240:  //
2241:  // See the guidelines above for deciding between `FAILED_PRECONDITION`,
2242:  // `ABORTED`, and `UNAVAILABLE`.
2243:  //
2244:  // HTTP Mapping: 503 Service Unavailable
2245:  UNAVAILABLE = 14;
2246:  // Unrecoverable data loss or corruption.
2247:  //
2248:  // HTTP Mapping: 500 Internal Server Error
2249:  DATA_LOSS = 15;
...

2875:  // Unless required by applicable law or agreed to in writing, software
2876:  // distributed under the License is distributed on an "AS IS" BASIS,
2877:  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2878:  // See the License for the specific language governing permissions and
2879:  // limitations under the License.
2880:  syntax = "proto3";
2881:  package google.rpc;
2882:  import "google/protobuf/any.proto";
2883:  import "kurrentdb/protocols/v1/code.proto";
2884:  option cc_enable_arenas = true;
2885:  option go_package = "google.golang.org/genproto/googleapis/rpc/status;status";
2886:  option java_multiple_files = true;
2887:  option java_outer_classname = "StatusProto";
2888:  option java_package = "com.google.rpc";
2889:  option objc_class_prefix = "RPC";
2890:  // The `Status` type defines a logical error model that is suitable for
2891:  // different programming environments, including REST APIs and RPC APIs. It is
2892:  // used by [gRPC](https://github.com/grpc). Each `Status` message contains
2893:  // three pieces of data: error code, error message, and error details.
2894:  //
2895:  // You can find out more about this error model and how to work with it in the
2896:  // [API Design Guide](https://cloud.google.com/apis/design/errors).
2897:  message Status {
2898:  // The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code].
2899:  google.rpc.Code code = 1;
2900:  // A developer-facing error message, which should be in English. Any
2901:  // user-facing error message should be localized and sent in the
2902:  // [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client.
2903:  string message = 2;
2904:  // A list of messages that carry the error details.  There is a common set of
2905:  // message types for APIs to use.
...

3141:  oneof deadline_option {
3142:  google.protobuf.Timestamp deadline_21_10_0 = 6;
3143:  google.protobuf.Duration deadline = 7;
3144:  }
3145:  }
3146:  message ProposedMessage {
3147:  event_store.client.UUID id = 1;
3148:  map<string, string> metadata = 2;
3149:  bytes custom_metadata = 3;
3150:  bytes data = 4;
3151:  }
3152:  }
3153:  message BatchAppendResp {
3154:  event_store.client.UUID correlation_id = 1;
3155:  oneof result {
3156:  google.rpc.Status error = 2;
3157:  Success success = 3;
...

3308:  }
3309:  message ResetPasswordReq {
3310:  Options options = 1;
3311:  message Options {
3312:  string login_name = 1;
3313:  string new_password = 2;
3314:  }
3315:  }
3316:  message ResetPasswordResp {
3317:  }
3318:  // ******************************************************************************************
3319:  // This protocol is UNSTABLE in the sense of being subject to change.
3320:  // ******************************************************************************************
3321:  syntax = "proto3";
3322:  package kurrent.rpc;
3323:  option csharp_namespace = "KurrentDB.Protocol.V2.Common.Errors";
3324:  import "kurrentdb/protocols/v2/rpc.proto";
3325:  // The canonical server error codes for the Kurrent Platform gRPC APIs.
3326:  // These errors represent common failure modes across all Kurrent services.
3327:  enum ServerError {
3328:  // Default value. This value is not used.
3329:  // An error code MUST always be set to a non-zero value.
3330:  // If an error code is not explicitly set, it MUST be treated as
3331:  // an internal server error (INTERNAL).
3332:  UNSPECIFIED = 0;
3333:  // Authentication or authorization failure.
3334:  // The client lacks valid credentials or sufficient permissions to perform the requested operation.
3335:  //
3336:  // Common causes:
3337:  // - Missing or invalid authentication tokens
3338:  // - Insufficient permissions for the operation
3339:  // - Expired credentials
3340:  //
3341:  // Client action: Check credentials, verify permissions, and re-authenticate if necessary.
3342:  // Not retriable without fixing the underlying authorization issue.
3343:  SERVER_ERROR_ACCESS_DENIED = 1 [(kurrent.rpc.error) = {
3344:  status_code: PERMISSION_DENIED,
3345:  has_details: true
3346:  }];
3347:  // The request is malformed or contains invalid data.
3348:  // The server cannot process the request due to client error.
3349:  //
3350:  // Common causes:
3351:  // - Invalid field values (e.g., empty required fields, out-of-range numbers)
3352:  // - Malformed data formats
3353:  // - Validation failures
3354:  //
3355:  // Client action: Fix the request data and retry.
3356:  // Not retriable without modifying the request.
3357:  SERVER_ERROR_BAD_REQUEST = 2 [(kurrent.rpc.error) = {
3358:  status_code: INVALID_ARGUMENT,
3359:  has_details: true
3360:  }];
3361:  // The server is not the cluster leader and cannot process write operations.
3362:  // In a clustered deployment, only the leader node can accept write operations.
3363:  //
3364:  // Common causes:
3365:  // - Client connected to a follower node
3366:  // - Leader election in progress
3367:  // - Network partition
3368:  //
3369:  // Client action: Redirect the request to the leader node indicated in the error details.
3370:  // Retriable after redirecting to the correct leader node.
3371:  SERVER_ERROR_NOT_LEADER_NODE = 5 [(kurrent.rpc.error) = {
3372:  status_code: FAILED_PRECONDITION,
3373:  has_details: true
3374:  }];
3375:  // The operation did not complete within the configured timeout period.
3376:  //
3377:  // Common causes:
3378:  // - Slow disk I/O during writes
3379:  // - Cluster consensus delays
3380:  // - Network latency
3381:  // - Heavy server load
3382:  //
3383:  // Client action: Retry with exponential backoff. Consider increasing timeout values.
3384:  // Retriable - the operation may succeed on retry.
3385:  SERVER_ERROR_OPERATION_TIMEOUT = 6 [(kurrent.rpc.error) = {
3386:  status_code: DEADLINE_EXCEEDED
3387:  }];
3388:  // The server is starting up or shutting down and cannot process requests.
3389:  //
3390:  // Common causes:
3391:  // - Server is initializing (loading indexes, recovering state)
3392:  // - Server is performing graceful shutdown
3393:  // - Server is performing maintenance operations
3394:  //
3395:  // Client action: Retry with exponential backoff. Wait for server to become ready.
3396:  // Retriable - the server will become available after initialization completes.
3397:  SERVER_ERROR_SERVER_NOT_READY = 7 [(kurrent.rpc.error) = {
3398:  status_code: UNAVAILABLE
3399:  }];
3400:  // The server is temporarily overloaded and cannot accept more requests.
3401:  // This is a backpressure mechanism to prevent server overload.
3402:  //
3403:  // Common causes:
3404:  // - Too many concurrent requests
3405:  // - Resource exhaustion (CPU, memory, disk I/O)
3406:  // - Rate limiting triggered
3407:  //
3408:  // Client action: Retry with exponential backoff. Reduce request rate.
3409:  // Retriable - the server may accept requests after load decreases.
3410:  SERVER_ERROR_SERVER_OVERLOADED = 8 [(kurrent.rpc.error) = {
3411:  status_code: UNAVAILABLE
3412:  }];
3413:  // An internal server error occurred.
3414:  // This indicates a bug or unexpected condition in the server.
3415:  //
3416:  // Common causes:
3417:  // - Unhandled exceptions
3418:  // - Assertion failures
3419:  // - Corrupted internal state
3420:  // - Programming errors
3421:  //
3422:  // Client action: Report to server administrators with request details.
3423:  // May be retriable, but likely indicates a server-side issue requiring investigation.
3424:  SERVER_ERROR_SERVER_MALFUNCTION = 9 [(kurrent.rpc.error) = {
3425:  status_code: INTERNAL
3426:  }];
3427:  }
3428:  // Details for ACCESS_DENIED errors.
3429:  message AccessDeniedErrorDetails {
3430:  // The friendly name of the operation that was denied.
3431:  string operation = 1;
3432:  // The username of the user who was denied access.
3433:  optional string username = 2;
3434:  // The permission that was required for this operation.
3435:  optional string permission = 3;
3436:  }
3437:  // Details for NOT_LEADER_NODE errors.
3438:  message NotLeaderNodeErrorDetails {
3439:  // Information about the current cluster leader node.
...

3444:  string host = 1;
3445:  // The gRPC port of the node.
3446:  int32 port = 2;
3447:  // The unique instance ID of the node.
3448:  optional string node_id = 3;
3449:  }
3450:  }
3451:  // ******************************************************************************************
3452:  // This protocol is UNSTABLE in the sense of being subject to change.
3453:  // ******************************************************************************************
3454:  syntax = "proto3";
3455:  package kurrent.rpc;
3456:  option csharp_namespace = "Kurrent.Rpc";
3457:  import "google/protobuf/descriptor.proto";
3458:  import "kurrentdb/protocols/v1/code.proto";
3459:  // ErrorMetadata provides actionable information for error enum values to enable automated
3460:  // code generation, documentation, and consistent error handling across the Kurrent platform.
3461:  //
3462:  // It was modeled to support a single details type per error code to simplify code generation and
3463:  // validation. If multiple detail types are needed for a single error code, consider defining
3464:  // separate error codes for each detail type. Or, use a union type (oneof) in the detail message
3465:  // to encapsulate multiple detail variants within a single detail message.
3466:  //
3467:  // More however DebugInfo and RetryInfo can and should be added to any error regardless of
3468:  // this setting, when applicable.
3469:  //
3470:  // This annotation is applied to enum values using the google.protobuf.EnumValueOptions
3471:  // extension mechanism. It enables:
3472:  // - Automatic gRPC status code mapping
3473:  // - Code generation for error handling utilities
3474:  // - Documentation generation
3475:  // - Type-safe error detail validation
3476:  //
3477:  // Usage Example:
3478:  //   enum StreamErrorCode {
3479:  //     REVISION_CONFLICT = 5 [(kurrent.rpc.error) = {
3480:  //       status_code: FAILED_PRECONDITION,
3481:  //       has_details: true
3482:  //     }];
3483:  //   }
3484:  //
3485:  // See individual field documentation for conventions and defaults.
3486:  message ErrorMetadata {
3487:  // Maps the error to a standard gRPC status code for transport-level compatibility.
3488:  // This field is REQUIRED for every error annotation.
3489:  //
3490:  // Use standard gRPC status codes from `google.rpc.code`.
3491:  //
3492:  // Code generators use this to:
3493:  // - Map errors to gRPC status codes automatically
3494:  // - Generate HTTP status code mappings
3495:  // - Create transport-agnostic error handling
3496:  google.rpc.Code status_code = 1;
3497:  // Indicates whether this error supports rich, typed detail messages.
3498:  // Defaults to false (simple message string only).
3499:  // The message type name must be derived from the enum name by convention.
3500:  // Mask: {EnumValue}ErrorDetails, {EnumValue}Error, {EnumValue}
3501:  //
3502:  // Examples:
3503:  //   ACCESS_DENIED    -> "AccessDeniedErrorDetails", "AccessDeniedError" or "AccessDenied"
3504:  //   SERVER_NOT_READY -> "ServerNotReadyErrorDetails", "ServerNotReadyError" or "ServerNotReady"
3505:  //
3506:  // Code generators use the message type name to:
3507:  // - Validate that the detail message matches the expected type
3508:  // - Generate type-safe error handling code
3509:  // - Create accurate documentation
3510:  bool has_details = 2;
3511:  }
3512:  // Extend EnumValueOptions to include error information for enum values
3513:  extend google.protobuf.EnumValueOptions {
3514:  // Provides additional information about error conditions for automated
3515:  // code generation and documentation.
3516:  optional ErrorMetadata error = 50000;
3517:  }
3518:  // ******************************************************************************************
3519:  // This protocol is UNSTABLE in the sense of being subject to change.
3520:  // ******************************************************************************************
3521:  syntax = "proto3";
3522:  package kurrentdb.protocol.v2.streams.errors;
3523:  option csharp_namespace = "KurrentDB.Protocol.V2.Streams.Errors";
3524:  import "kurrentdb/protocols/v2/rpc.proto";
3525:  // Error codes specific to the Streams API.
3526:  // These errors represent failure modes when working with streams of records.
3527:  enum StreamsError {
3528:  // Default value. This value is not used.
3529:  // An error code MUST always be set to a non-zero value.
3530:  // If an error code is not explicitly set, it MUST be treated as
3531:  // an internal server error (INTERNAL).
3532:  STREAMS_ERROR_UNSPECIFIED = 0;
3533:  // The requested stream does not exist in the database.
3534:  //
3535:  // Common causes:
3536:  // - Stream name typo or incorrect stream identifier
3537:  // - Stream was never created (no events appended yet)
3538:  // - Stream was deleted and not yet recreated
3539:  //
3540:  // Client action: Verify the stream name is correct. Create the stream by appending to it.
3541:  // Recoverable by creating the stream first (append with NO_STREAM expected revision).
3542:  STREAMS_ERROR_STREAM_NOT_FOUND = 1 [(kurrent.rpc.error) = {
3543:  status_code: NOT_FOUND,
3544:  has_details: true,
3545:  }];
3546:  // The stream already exists when an operation expected it not to exist.
3547:  //
3548:  // Common causes:
3549:  // - Attempting to create a stream that already has events
3550:  // - Using NO_STREAM expected revision on an existing stream
3551:  // - Race condition with concurrent stream creation
3552:  //
3553:  // Client action: Use the existing stream or use a different expected revision.
3554:  // Recoverable by adjusting the expected revision or using the existing stream.
3555:  STREAMS_ERROR_STREAM_ALREADY_EXISTS = 2 [(kurrent.rpc.error) = {
3556:  status_code: ALREADY_EXISTS,
3557:  has_details: true
3558:  }];
3559:  // The stream has been soft deleted.
3560:  // Soft-deleted streams are hidden from stream lists but can be restored by appending to them.
3561:  //
3562:  // Common causes:
3563:  // - Stream was explicitly soft-deleted via delete operation
3564:  // - Attempting to read from a soft-deleted stream
3565:  //
3566:  // Client action: Restore the stream by appending new events, or accept that the stream is deleted.
3567:  // Recoverable by appending to the stream to restore it.
3568:  STREAMS_ERROR_STREAM_DELETED = 3 [(kurrent.rpc.error) = {
3569:  status_code: FAILED_PRECONDITION,
3570:  has_details: true
3571:  }];
3572:  // The stream has been tombstoned (permanently deleted).
3573:  // Tombstoned streams cannot be restored and will never accept new events.
3574:  //
3575:  // Common causes:
3576:  // - Stream was explicitly tombstoned via tombstone operation
3577:  // - Administrative deletion of sensitive data
3578:  // - Attempting to write to or read from a tombstoned stream
3579:  //
3580:  // Client action: Stream is permanently removed. Create a new stream with a different name if needed.
3581:  // Not recoverable - the stream cannot be restored.
3582:  STREAMS_ERROR_STREAM_TOMBSTONED = 4 [(kurrent.rpc.error) = {
3583:  status_code: FAILED_PRECONDITION,
3584:  has_details: true
3585:  }];
3586:  // The expected revision does not match the actual stream revision.
3587:  // This is an optimistic concurrency control failure.
3588:  //
3589:  // Common causes:
3590:  // - Another client modified the stream concurrently
3591:  // - Client has stale state about the stream revision
3592:  // - Race condition in distributed system
3593:  //
3594:  // Client action: Fetch the current stream revision and retry with the correct expected revision.
3595:  // Recoverable by reading the current state and retrying with proper optimistic concurrency control.
3596:  STREAMS_ERROR_STREAM_REVISION_CONFLICT = 5 [(kurrent.rpc.error) = {
3597:  status_code: FAILED_PRECONDITION,
3598:  has_details: true
3599:  }];
3600:  // A single record being appended exceeds the maximum allowed size.
3601:  //
3602:  // Common causes:
3603:  // - Record payload is too large (exceeds server's max record size configuration)
3604:  // - Excessive metadata in properties
3605:  // - Large binary data without chunking
3606:  //
3607:  // Client action: Reduce record size, split large payloads across multiple records, or increase server limits.
3608:  // Recoverable by reducing record size or adjusting server configuration.
3609:  STREAMS_ERROR_APPEND_RECORD_SIZE_EXCEEDED = 6 [(kurrent.rpc.error) = {
3610:  status_code: INVALID_ARGUMENT,
3611:  has_details: true
3612:  }];
3613:  // The total size of all records in a single append session exceeds the maximum allowed transaction size.
3614:  //
3615:  // Common causes:
3616:  // - Too many records in a single append session
3617:  // - Combined payload size exceeds server's max transaction size
3618:  // - Attempting to write very large batches
3619:  //
3620:  // Client action: Split the append into multiple smaller transactions.
3621:  // Recoverable by reducing the number of records per append session.
3622:  STREAMS_ERROR_APPEND_TRANSACTION_SIZE_EXCEEDED = 7 [(kurrent.rpc.error) = {
3623:  status_code: ABORTED,
3624:  has_details: true
3625:  }];
3626:  // The same stream appears multiple times in a single append session.
3627:  // This is currently not supported to prevent complexity with expected revisions and ordering.
3628:  //
3629:  // Common causes:
3630:  // - Accidentally appending to the same stream twice in one session
3631:  // - Application logic error in batch operations
3632:  //
3633:  // Client action: Remove duplicate streams from the append session or split into multiple sessions.
3634:  // Recoverable by restructuring the append session to reference each stream only once.
3635:  STREAMS_ERROR_STREAM_ALREADY_IN_APPEND_SESSION = 8 [(kurrent.rpc.error) = {
3636:  status_code: ABORTED,
3637:  has_details: true
3638:  }];
3639:  // An append session was started but no append requests were sent before completing the stream.
3640:  //
3641:  // Common causes:
3642:  // - Client completed the stream without sending any AppendRequest messages
3643:  // - Application logic error
3644:  //
3645:  // Client action: Ensure at least one AppendRequest is sent before completing the stream.
3646:  // Recoverable by properly implementing the append session protocol.
3647:  STREAMS_ERROR_APPEND_SESSION_NO_REQUESTS = 9 [(kurrent.rpc.error) = {
3648:  status_code: FAILED_PRECONDITION
3649:  }];
3650:  // One or more consistency checks failed during an AppendRecords operation.
3651:  // The transaction is aborted — no records are written.
3652:  //
3653:  // Common causes:
3654:  // - A stream state check found the stream at a different revision than expected
3655:  // - A stream referenced in a state check does not exist, was deleted, or was tombstoned
3656:  //
3657:  // Client action: Inspect the AppendConsistencyViolationErrorDetails to determine which
3658:  // checks failed and why, then correct the request or refresh local state and retry.
3659:  // Recoverable by reading the current state and resubmitting with updated checks.
3660:  STREAMS_ERROR_APPEND_CONSISTENCY_VIOLATION = 14 [(kurrent.rpc.error) = {
3661:  status_code: FAILED_PRECONDITION,
3662:  has_details: true
3663:  }];
3664:  }
3665:  // Details for STREAM_NOT_FOUND errors.
3666:  message StreamNotFoundErrorDetails {
3667:  // The name of the stream that was not found.
3668:  string stream = 1;
3669:  }
3670:  // Details for STREAM_ALREADY_EXISTS errors.
3671:  message StreamAlreadyExistsErrorDetails {
3672:  // The name of the stream that already exists.
3673:  string stream = 1;
3674:  }
3675:  // Details for STREAM_DELETED errors.
3676:  message StreamDeletedErrorDetails {
3677:  // The name of the stream that was deleted.
3678:  string stre...

@w1am w1am force-pushed the w1am/fix-default-deadline-doc branch from 250a2ad to e7f1d2c Compare April 30, 2026 11:52
@w1am w1am added cherry-pick:release/v1.1 Cherry picks PR into v1.1 release branch cherry-pick:release/v1.2 cherry-pick:release/v1.0 Cherry picks PR into v1.0 release branch labels Apr 30, 2026
@w1am w1am force-pushed the w1am/fix-default-deadline-doc branch from e7f1d2c to cacec59 Compare April 30, 2026 11:55
@w1am w1am force-pushed the w1am/fix-default-deadline-doc branch from cacec59 to 4523fe1 Compare April 30, 2026 12:00
@w1am w1am merged commit 867d369 into master Apr 30, 2026
@w1am w1am deleted the w1am/fix-default-deadline-doc branch April 30, 2026 12:01
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@w1am 👉 Created pull request targeting release/v1.0: #495

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@w1am 👉 Created pull request targeting release/v1.1: #496

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@w1am 👉 Created pull request targeting release/v1.2: #497

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cherry-pick:release/v1.0 Cherry picks PR into v1.0 release branch cherry-pick:release/v1.1 Cherry picks PR into v1.1 release branch cherry-pick:release/v1.2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant