Errors & Exceptions
Relevant source files
The following files were used as context for generating this wiki page:
- crates/crucible-codegen-docs/src/markdown.rs
- crates/crucible-codegen-common/src/guide.rs
- crates/crucible-codegen-go/src/lib.rs
- crates/crucible-codegen-ruby/src/lib.rs
- crates/crucible-codegen-rust/tests/golden/permissions.rs
- crates/crucible-codegen-ts/src/snippet.rs
- crates/crucible-codegen-dart/src/snippet.rs
Crucible provides a unified framework for defining, transmitting, and handling errors across server implementations and client SDKs. Errors are modeled in the service definition, allowing generators to produce language-native exception classes that carry structured metadata, HTTP status codes, and retry instructions.
The system distinguishes between modeled errors (defined in the IDL) and runtime errors (transport failures, timeouts, or cancellations). This ensures that clients can differentiate between a service-level validation failure and a network-level connectivity issue.
Error Architecture and Metadata
Every modeled error in Crucible includes specific metadata used by the runtime to handle the response. This metadata is extracted from the service model and embedded into the generated code and documentation.
Core Error Fields
| Field | Description |
|---|---|
| Code | The machine-readable string identifier for the error (e.g., ValidationException). |
| HTTP Status | The status code sent on the wire (e.g., 400, 404, 500). |
| Fault | Identifies if the error is a Client fault (invalid request) or a Server fault (internal failure). |
| Retryable | Indicates if the call can be safely retried. Includes a throttling flag for rate-limiting scenarios. |
Sources: crates/crucible-codegen-docs/src/markdown.rs:693-710, crates/crucible-codegen-rust/tests/golden/permissions.rs:434-444
Error Communication Flow
When a server encounters an error, it serializes the error shape into a JSON body and attaches a discriminator header to identify the error type.
The X-Crucible-Error header (or a configured equivalent) allows the client to identify the error type without fully parsing the JSON body first.
Sources: crates/crucible-codegen-docs/src/markdown.rs:723-736, crates/crucible-codegen-go/src/lib.rs:374-385
Modeled Error Implementation
Generators produce specific structures or classes for each error defined in the service model. These structures typically implement a ServiceError interface or extend a base ServiceException class.
Rust Implementation
In Rust, errors are generated as structs that implement the ModelledError trait. This trait provides methods for accessing error info, such as the shape ID and fault type.
pub struct ValidationException {
pub message: String,
pub reason: ValidationExceptionReason,
pub field_list: Option<ValidationExceptionFieldList>,
}
impl ModelledError for ValidationException {
fn shape_id(&self) -> &'static str { "crucible.errors#ValidationException" }
fn info(&self) -> &'static ErrorInfo { &VALIDATION_EXCEPTION_INFO }
}
Sources: crates/crucible-codegen-rust/tests/golden/permissions.rs:504-511, crates/crucible-codegen-rust/tests/golden/permissions.rs:528-534
Go Implementation
Go clients use a modeledError switch to decode JSON values into the correct concrete pointer type based on the target string provided by the runtime.
func modeledError(target string, values map[string]any, metadata *ServiceError) error {
switch target {
case "crucible.errors#ValidationException":
result := &ValidationException{Metadata: metadata}
decodeModel(wireSchema, target, values, result)
return result
}
return metadata
}
Sources: crates/crucible-codegen-go/src/lib.rs:374-385
Runtime and Transport Errors
SDKs handle failures that occur before a response is received or due to environment constraints.
- NetworkError / NetworkException: Thrown when no response arrives from the service (e.g., DNS failure, connection reset).
- DeadlineError / TimeoutException: Thrown when the call exceeds the configured
timeout. - CancelledError / CancelledException: Thrown when a
CancellationTokenorcontext.Contextis cancelled by the caller. - ServiceException / UnknownServiceError: A fallback for error responses that the client model does not recognize.
Sources: crates/crucible-codegen-ruby/src/lib.rs:25-28, crates/crucible-codegen-ts/src/snippet.rs:326-330, crates/crucible-codegen-dart/src/snippet.rs:360-366
Retries and Idempotency
The Crucible runtime automatically applies retry logic with backoff based on the safety of the operation and the nature of the error.
Retry Rules
- Throttling Errors: Always retried for any operation.
- Transport Failures: Retried only for read-only or idempotent operations.
- HTTP 500, 502, 503, 504: Treated as potentially transient server-side issues and retried if the operation carries an idempotency token.
- Idempotency Tokens: If a caller leaves the token unset, the client generates one per call and reuses it across attempts to prevent duplicate processing on the server.
Sources: crates/crucible-codegen-common/src/guide.rs:207-210, crates/crucible-codegen-ts/src/snippet.rs:331-333
Retry Logic Flow
Language-Specific Exception Patterns
SDKs use the native error-handling paradigms of their respective languages to simplify integration for developers.
| Language | Catching Pattern | Metadata Access |
|---|---|---|
| TypeScript | if (error instanceof ValidationException) | error.$metadata.status |
| Dart | on ValidationException catch (error) | error.metadata.status |
| Ruby | rescue ValidationException => e | Native Ruby Exception |
| Go | errors.As(err, &valErr) | valErr.Metadata |
Sources: crates/crucible-codegen-ts/src/snippet.rs:260-265, crates/crucible-codegen-dart/src/snippet.rs:254-260, crates/crucible-codegen-go/src/lib.rs:358-365