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/queryendpoint (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-retrytransaction/3and multi-host failover treat it as retriable (the write was rejected, nothing applied).:invalid_begin_body— a malformedisolationLevelin a transaction-begin body.:server_error— the generic fallback: an unrecognized HTTP 400 body, or anexceptionFQN that matches none of the above.
Client-side (raised BY arcadic, never by the server — the statement never left the process):
:use_explain—query/command(either transport) orquery_stream(HTTP) was called on a statement that already carries anEXPLAIN/PROFILEprefix, which returns a plan rather than rows; callexplain/4/profile/4instead. The guard is response-layer: HTTP viaArcadic.Result.normalize/1, Bolt via theexecute/4plan-presence check.:not_supported— the active transport doesn't implement the called capability (e.g.explain/4against a transport without it, HTTP streaming inside a transaction, Bolt's admin-only calls, async writes withoutexecute_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
@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
@spec from_response(pos_integer(), map()) :: t()
Build an Arcadic.Error from an HTTP status and a decoded ArcadeDB error body.