Arcadic.Error exception (Arcadic v0.7.1)

Copy Markdown View Source

A server-returned ArcadeDB error, normalized to a typed reason.

detail (statement-shape text — value-free under the params-only rule) is a struct field for debugging, but is QUARANTINED: it appears in neither Exception.message/1 nor inspect/1 (AGENTS.md Critical Rule 3). Reach it only via explicit error.detail.

reason taxonomy

Server-derived (mapped from the HTTP status and/or the ArcadeDB exception FQN in from_response/2):

  • :not_idempotent — a write reached the read-only /query endpoint (QueryNotIdempotentException).
  • :parse_error — the statement failed to parse (Parsing/ParseException).
  • :unauthorized — bad credentials, or an HTTP 403 (SecurityException).
  • :database_not_found — the target database doesn't exist (DatabaseOperationException).
  • :transaction_error — a transaction-lifecycle failure, both server-derived (TransactionException) and client-raised (no active/already-open session; a Bolt commit failure).
  • :concurrent_modification — an optimistic-concurrency conflict (ConcurrentModificationException/NeedRetryException).
  • :duplicate_key — a unique-index violation (DuplicatedKeyException).
  • :timeout — the server reported a timeout (TimeoutException).
  • :not_leader — the target node is not the cluster leader and could not forward the write (ServerIsNotTheLeaderException, HTTP 400). A managed-retry transaction/3 and multi-host failover treat it as retriable (the write was rejected, nothing applied).
  • :invalid_begin_body — a malformed isolationLevel in a transaction-begin body.
  • :server_error — the generic fallback: an unrecognized HTTP 400 body, or an exception FQN that matches none of the above.

Client-side (raised BY arcadic, never by the server — the statement never left the process):

  • :use_explainquery/command (either transport) or query_stream (HTTP) was called on a statement that already carries an EXPLAIN/PROFILE prefix, which returns a plan rather than rows; call explain/4/profile/4 instead. The guard is response-layer: HTTP via Arcadic.Result.normalize/1, Bolt via the execute/4 plan-presence check.
  • :not_supported — the active transport doesn't implement the called capability (e.g. explain/4 against a transport without it, HTTP streaming inside a transaction, Bolt's admin-only calls, async writes without execute_async/3).
  • :unexpected_response — a 2xx response whose body is off the documented contract (client-raised by the time-series read paths; the body is never echoed).

A separate, non-Arcadic.Error convention: several admin validators reject bad input as a bare atom tuple, never this struct, and never echoing the offending value — {:error, :invalid_identifier} (Arcadic.Identifier.validate/1, e.g. a bad database/type name), {:error, :invalid_setting_key} / {:error, :invalid_setting_value} (Arcadic.Server.set_server_setting/3 and set_database_setting/3), {:error, :invalid_url} (Arcadic.Backup.backup/2's :to target and restore/3's source URL, via Arcadic.Identifier.validate_url/1), {:error, :invalid_user_spec} (Arcadic.Security.create_user/2 — an unencodable user spec, e.g. a non-UTF-8 password), {:error, :unencodable_body} (Arcadic.Function.define/4 and Arcadic.Trigger.create/4 — a body containing the sole breakout byte, a backslash, or a control/line byte, none of which ArcadeDB's "..." DDL literal can escape), and, from Arcadic.Changes, {:error, :mint_web_socket_not_available} (start_link/1, when the optional mint_web_socket dependency is absent), {:error, :subscriber_conflict} (subscribe/3, a second subscriber pid on an already-bound process), and the start_link/1 conn-shape rejections {:error, :invalid_conn} (no/invalid :conn), {:error, :invalid_auth} (an auth shape other than {user, pass} / {:bearer, token}), {:error, :invalid_url_scheme} (a base_url scheme outside http/https/ws/wss — guards against a silent plaintext downgrade), and {:error, :invalid_max_buffer} (a non-positive-integer :max_buffer).

Summary

Functions

Build an Arcadic.Error from an HTTP status and a decoded ArcadeDB error body.

Types

t()

@type t() :: %Arcadic.Error{
  __exception__: true,
  detail: String.t() | nil,
  exception: String.t() | nil,
  http_status: pos_integer() | nil,
  message: String.t() | nil,
  reason: atom()
}

Functions

from_response(status, body)

@spec from_response(pos_integer(), map()) :: t()

Build an Arcadic.Error from an HTTP status and a decoded ArcadeDB error body.