Handle Errors and Request IDs

Mutation failures are structured so callers can classify failures without parsing internal exception text.

Classify failures

  • Validation: submitted properties, parameters, or references violate the template or command contract.
  • Authorization: caller lacks permission for namespace or target.
  • Conflict: revision is stale, idempotency key is reused for another command, or on_existing="raise" detects duplicate.
  • Connection: client cannot reach server or receives rejected HTTP response.

Local builders raise domain exceptions such as ExistingResourceError. Remote clients expose RecapConnectionError for transport failures and RecapHTTPError for rejected responses. HTTP errors include status code and, when supplied by server, request_id.

Use request IDs in diagnostics

Every server response carries X-Request-ID; structured error bodies also carry that identifier:

X-Request-ID: 6f4c2f08-...

Return opaque value to operators when reporting failure. Do not expose API keys, authorization headers, internal tracebacks, or sensitive property and parameter values in user-facing errors.

Rely on atomic mutation behavior

Failed mutations roll back database changes without retaining partial state. The current REST server does not persist failure audits; use its request ID to correlate a rejected response with server diagnostics.

from recap.exceptions import ExistingResourceError

try:
    with namespace.build_resource(resource_id=plate.id) as builder:
        builder.set_props({"dimensions": {"rows": -1}})
except ExistingResourceError as exc:
    print(f"Local mutation failed: {exc}")