Skip to content

Commit 87a3d5a

Browse files
committed
Fixup
1 parent ccd0104 commit 87a3d5a

5 files changed

Lines changed: 304 additions & 188 deletions

File tree

src/main/java/io/kurrent/dbclient/MultiStreamAppend.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.google.protobuf.ByteString;
44
import com.google.protobuf.Value;
5+
import com.google.rpc.ErrorInfo;
56
import io.grpc.StatusRuntimeException;
67
import io.grpc.stub.StreamObserver;
78
import io.grpc.stub.ClientResponseObserver;

src/main/proto/kurrentdb/protocol/v2/errors.proto

Lines changed: 98 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
syntax = "proto3";
66

7-
package kurrentdb.protocol.v2.common.errors;
7+
package kurrent.rpc;
88

99
option go_package = "github.com/kurrent-io/KurrentDB-Client-Go/protos/kurrentdb/protocols/v2/common/errors";
1010
option csharp_namespace = "KurrentDB.Protocol.V2.Common.Errors";
@@ -13,138 +13,143 @@ option java_multiple_files = true;
1313

1414
import "kurrentdb/protocol/v2/rpc.proto";
1515

16-
enum CommonError {
16+
// The canonical server error codes for the Kurrent Platform gRPC APIs.
17+
// These errors represent common failure modes across all Kurrent services.
18+
enum ServerError {
1719
// Default value. This value is not used.
1820
// An error code MUST always be set to a non-zero value.
1921
// If an error code is not explicitly set, it MUST be treated as
2022
// an internal server error (INTERNAL).
2123
UNSPECIFIED = 0;
2224

23-
COMMON_ERROR_ACCESS_DENIED = 1 [(kurrent.rpc.error) = {
25+
// Authentication or authorization failure.
26+
// The client lacks valid credentials or sufficient permissions to perform the requested operation.
27+
//
28+
// Common causes:
29+
// - Missing or invalid authentication tokens
30+
// - Insufficient permissions for the operation
31+
// - Expired credentials
32+
//
33+
// Client action: Check credentials, verify permissions, and re-authenticate if necessary.
34+
// Not retriable without fixing the underlying authorization issue.
35+
SERVER_ERROR_ACCESS_DENIED = 1 [(kurrent.rpc.error) = {
2436
status_code: PERMISSION_DENIED,
2537
has_details: true
2638
}];
2739

28-
COMMON_ERROR_INVALID_REQUEST = 2 [(kurrent.rpc.error) = {
40+
// The request is malformed or contains invalid data.
41+
// The server cannot process the request due to client error.
42+
//
43+
// Common causes:
44+
// - Invalid field values (e.g., empty required fields, out-of-range numbers)
45+
// - Malformed data formats
46+
// - Validation failures
47+
//
48+
// Client action: Fix the request data and retry.
49+
// Not retriable without modifying the request.
50+
SERVER_ERROR_BAD_REQUEST = 2 [(kurrent.rpc.error) = {
2951
status_code: INVALID_ARGUMENT,
3052
has_details: true
3153
}];
3254

33-
COMMON_ERROR_NOT_LEADER_NODE = 5 [(kurrent.rpc.error) = {
55+
// The server is not the cluster leader and cannot process write operations.
56+
// In a clustered deployment, only the leader node can accept write operations.
57+
//
58+
// Common causes:
59+
// - Client connected to a follower node
60+
// - Leader election in progress
61+
// - Network partition
62+
//
63+
// Client action: Redirect the request to the leader node indicated in the error details.
64+
// Retriable after redirecting to the correct leader node.
65+
SERVER_ERROR_NOT_LEADER_NODE = 5 [(kurrent.rpc.error) = {
3466
status_code: FAILED_PRECONDITION,
3567
has_details: true
3668
}];
3769

38-
COMMON_ERROR_OPERATION_TIMEOUT = 6 [(kurrent.rpc.error) = {
70+
// The operation did not complete within the configured timeout period.
71+
//
72+
// Common causes:
73+
// - Slow disk I/O during writes
74+
// - Cluster consensus delays
75+
// - Network latency
76+
// - Heavy server load
77+
//
78+
// Client action: Retry with exponential backoff. Consider increasing timeout values.
79+
// Retriable - the operation may succeed on retry.
80+
SERVER_ERROR_OPERATION_TIMEOUT = 6 [(kurrent.rpc.error) = {
3981
status_code: DEADLINE_EXCEEDED
4082
}];
4183

42-
COMMON_ERROR_SERVER_NOT_READY = 7 [(kurrent.rpc.error) = {
84+
// The server is starting up or shutting down and cannot process requests.
85+
//
86+
// Common causes:
87+
// - Server is initializing (loading indexes, recovering state)
88+
// - Server is performing graceful shutdown
89+
// - Server is performing maintenance operations
90+
//
91+
// Client action: Retry with exponential backoff. Wait for server to become ready.
92+
// Retriable - the server will become available after initialization completes.
93+
SERVER_ERROR_SERVER_NOT_READY = 7 [(kurrent.rpc.error) = {
4394
status_code: UNAVAILABLE
4495
}];
4596

46-
COMMON_ERROR_SERVER_OVERLOADED = 8 [(kurrent.rpc.error) = {
97+
// The server is temporarily overloaded and cannot accept more requests.
98+
// This is a backpressure mechanism to prevent server overload.
99+
//
100+
// Common causes:
101+
// - Too many concurrent requests
102+
// - Resource exhaustion (CPU, memory, disk I/O)
103+
// - Rate limiting triggered
104+
//
105+
// Client action: Retry with exponential backoff. Reduce request rate.
106+
// Retriable - the server may accept requests after load decreases.
107+
SERVER_ERROR_SERVER_OVERLOADED = 8 [(kurrent.rpc.error) = {
47108
status_code: UNAVAILABLE
48109
}];
49110

50-
COMMON_ERROR_SERVER_MALFUNCTION = 9 [(kurrent.rpc.error) = {
111+
// An internal server error occurred.
112+
// This indicates a bug or unexpected condition in the server.
113+
//
114+
// Common causes:
115+
// - Unhandled exceptions
116+
// - Assertion failures
117+
// - Corrupted internal state
118+
// - Programming errors
119+
//
120+
// Client action: Report to server administrators with request details.
121+
// May be retriable, but likely indicates a server-side issue requiring investigation.
122+
SERVER_ERROR_SERVER_MALFUNCTION = 9 [(kurrent.rpc.error) = {
51123
status_code: INTERNAL
52124
}];
53-
54-
// // The operation was aborted, typically due to a concurrency issue such as a
55-
// // sequencer conflict or transaction abort.
56-
// // This error will only be used when there is no intention to create a dedicated
57-
// // error code for the specific issue, perhaps because the issue is too generic
58-
// // or too transient or temporary in terms of handling.
59-
// OPERATION_ABORTED = 10 [(kurrent.rpc.error) = {
60-
// status_code: ABORTED
61-
// }];
62125
}
63126

127+
// Details for ACCESS_DENIED errors.
64128
message AccessDeniedErrorDetails {
65-
// The scope in which access was denied.
66-
// It could represent a resource, a domain, a permission type
67-
// or a "path" that is a combination of these.
68-
// (e.g., "stream:orders", "db:customers:read", etc.)
69-
optional string scope = 1;
129+
// The friendly name of the operation that was denied.
130+
string operation = 1;
70131

71132
// The username of the user who was denied access.
72133
optional string username = 2;
73-
}
74134

75-
message InvalidRequestErrorDetails {
76-
// Detailed information about each invalid argument.
77-
repeated FieldViolation violations = 1;
78-
79-
// Describes a single field violation.
80-
message FieldViolation {
81-
// A path that leads to a field in the request body. The value will be a
82-
// sequence of dot-separated identifiers that identify a protocol buffer
83-
// field.
84-
//
85-
// Consider the following:
86-
//
87-
// message CreateContactRequest {
88-
// message EmailAddress {
89-
// enum Type {
90-
// TYPE_UNSPECIFIED = 0;
91-
// HOME = 1;
92-
// WORK = 2;
93-
// }
94-
//
95-
// optional string email = 1;
96-
// repeated EmailType type = 2;
97-
// }
98-
//
99-
// string full_name = 1;
100-
// repeated EmailAddress email_addresses = 2;
101-
// }
102-
//
103-
// In this example, in proto `field` could take one of the following values:
104-
//
105-
// * `full_name` for a violation in the `full_name` value
106-
// * `email_addresses[1].email` for a violation in the `email` field of the
107-
// first `email_addresses` message
108-
// * `email_addresses[3].type[2]` for a violation in the second `type`
109-
// value in the third `email_addresses` message.
110-
//
111-
// In JSON, the same values are represented as:
112-
//
113-
// * `fullName` for a violation in the `fullName` value
114-
// * `emailAddresses[1].email` for a violation in the `email` field of the
115-
// first `emailAddresses` message
116-
// * `emailAddresses[3].type[2]` for a violation in the second `type`
117-
// value in the third `emailAddresses` message.
118-
string field = 1;
119-
120-
// A description of why the request element is bad.
121-
string description = 2;
122-
}
135+
// The permission that was required for this operation.
136+
optional string permission = 3;
123137
}
124138

139+
// Details for NOT_LEADER_NODE errors.
125140
message NotLeaderNodeErrorDetails {
126-
// The host of the current leader node
127-
string host = 1;
141+
// Information about the current cluster leader node.
142+
NodeInfo current_leader = 1;
128143

129-
// The port of the current leader node
130-
int32 port = 2;
144+
// Information about a cluster node.
145+
message NodeInfo {
146+
// The hostname or IP address of the node.
147+
string host = 1;
131148

132-
// The instance ID of the current leader node
133-
optional string node_id = 3;
134-
}
149+
// The gRPC port of the node.
150+
int32 port = 2;
135151

136-
message RetryInfoErrorDetails {
137-
// The duration in milliseconds after which the client can retry the operation.
138-
int32 retry_delay_ms = 1;
139-
}
140-
141-
message NodeInfoErrorDetails {
142-
// The host of the node
143-
string host = 1;
144-
145-
// The port of the node
146-
int32 port = 2;
147-
148-
// The instance ID of the node
149-
optional string node_id = 3;
152+
// The unique instance ID of the node.
153+
optional string node_id = 3;
154+
}
150155
}

src/main/proto/kurrentdb/protocol/v2/rpc.proto

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,11 @@ message ErrorMetadata {
5656
// Indicates whether this error supports rich, typed detail messages.
5757
// Defaults to false (simple message string only).
5858
// The message type name must be derived from the enum name by convention.
59-
// Mask: {EnumValue}ErrorDetails
59+
// Mask: {EnumValue}ErrorDetails, {EnumValue}Error, {EnumValue}
6060
//
6161
// Examples:
62-
// ACCESS_DENIED -> "AccessDeniedErrorDetails"
63-
// SERVER_NOT_READY -> "ServerNotReadyErrorDetails"
62+
// ACCESS_DENIED -> "AccessDeniedErrorDetails", "AccessDeniedError" or "AccessDenied"
63+
// SERVER_NOT_READY -> "ServerNotReadyErrorDetails", "ServerNotReadyError" or "ServerNotReady"
6464
//
6565
// Code generators use the message type name to:
6666
// - Validate that the detail message matches the expected type
@@ -75,20 +75,3 @@ extend google.protobuf.EnumValueOptions {
7575
// code generation and documentation.
7676
optional ErrorMetadata error = 50000;
7777
}
78-
79-
// The top-level error message that must be returned by any service or operation
80-
// in the Kurrent platform.
81-
message RequestErrorInfo {
82-
// The code must match one of the defined enum error codes from the module
83-
// where the error originated from.
84-
// A machine-readable error code that indicates the specific error condition.
85-
// This should be at most 63 characters and match a regular expression of
86-
// `[A-Z][A-Z0-9_]+[A-Z0-9]`, which represents UPPER_SNAKE_CASE.
87-
// By convention, it will be generated from the enum value name if not
88-
// explicitly specified.
89-
// Conventions:
90-
// - Prefix with the service name or domain to avoid collisions
91-
// - Use UPPER_SNAKE_CASE with only letters, numbers, and underscores
92-
// - Avoid redundant information (e.g., do not include "ERROR" suffix)
93-
string code = 1;
94-
}

0 commit comments

Comments
 (0)