Skip to content

Error handling#128

Open
kearfy wants to merge 11 commits intomainfrom
micha/error-handling
Open

Error handling#128
kearfy wants to merge 11 commits intomainfrom
micha/error-handling

Conversation

@kearfy
Copy link
Member

@kearfy kearfy commented Feb 24, 2026

Structured error handling for the Java SDK

Summary

This PR adds structured, typed error handling for errors originating from the SurrealDB server. Callers can catch specific exception types, inspect machine-readable error kinds and details, and walk the server-side cause chain when errors are nested.

What's included

Exception hierarchy

  • SurrealException — Base for all SDK errors (replaces the previous generic exception where applicable).
  • ServerException — Base for errors returned by the server. Exposes:
    • getKindEnum() — Error kind as an enum for type-safe matching (aligned with the Rust SDK’s ErrorDetails).
    • getKind() — Machine-readable kind string (for unknown kinds or when the raw wire value is needed).
    • getDetails() — Optional structured payload (e.g. which table was not found, auth variant).
    • getServerCause() — The next server error in the chain, if any.
  • Typed subclasses for known kinds: ValidationException, ConfigurationException, ThrownException, QueryException, SerializationException, NotAllowedException, NotFoundException, AlreadyExistsException, InternalException. Unknown kinds surface as ServerException for forward compatibility.

Convenience API

  • ErrorKind — Java enum aligned with the Rust SDK’s ErrorDetails variants (VALIDATION, NOT_FOUND, NOT_ALLOWED, etc.). Passed across the JNI boundary so the Java SDK relies on the Rust SDK for deserialization and variant mapping.
  • Detail-kind constants — e.g. NotFoundDetailKind.TABLE, AuthDetailKind.TOKEN_EXPIRED, for use with the detail helpers.
  • Subclass getters — e.g. NotFoundException.getTableName(), NotFoundException.getRecordId(), NotAllowedException.isTokenExpired(), QueryException.getTimeout(), so callers can work with typed details without parsing getDetails() by hand.
  • Cause-chain helpershasKind(ErrorKind) / hasKind(String), findCause(ErrorKind) / findCause(String) to traverse the chain and find a specific error kind.

Detail format

Details follow the SurrealDB wire format: a kind and optional nested details. The Java helpers support both the current internally-tagged format and the legacy externally-tagged format for compatibility with older servers. Subclass getters and the shared helpers (detailKind, detailField, getDetailString, etc.) work with both.

Native integration

The Rust/JNI layer matches on the Rust SDK’s ErrorDetails enum (from error.details()) to choose the Java exception class and the ErrorKind enum constant. It passes ErrorKind across the boundary (with an optional raw kind string for unknown variants), builds the cause chain from the error source chain, and converts typed details to Java objects (Map/String/Number) so the Java side receives a ready-to-use object tree without JSON parsing.

Testing

  • Unit tests cover the exception hierarchy, detail helpers, both detail formats, convenience getters, and cause-chain traversal.
  • Integration tests confirm that real server errors (e.g. parse errors, THROW statements) produce the expected exception types and details.

@kearfy kearfy marked this pull request as draft February 24, 2026 12:55
@kearfy kearfy marked this pull request as ready for review February 26, 2026 14:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant