Skip to content

Error Reference

Every public reject/error id the library can raise — what emits it, and what to do about it.

Error ids are API. Every id below is stable from v1 and safe to branch on; you program against the id, never the message string (messages are for humans and may be reworded). An error arrives as a NiceError — branch on it with err.hasId("..."), or narrow to a domain first with err_domain.isExact(err):

// doc-check: skip — illustrative branching against ids documented below
if (err_realm.isExact(e) && e.hasId("insufficient_security")) {
// handle the specific case
}

Realm rejections arrive on onMutationRejected (their .error is a NiceError); connection failures reject connect()/dispatch; validation failures come back as a typed action result. The tables group ids by the package that raises them.

Raised by the realm engine on attach and on each write/intent. A rejection here rolled back the optimistic effect (surfaced via onMutationRejected) or refused the attach (whenLive() rejects, realm.attachError is set).

IdWhat emits itWhat to do
schema_mismatchClient and server built from different realm definitions (hash mismatch).Redeploy so both ends share one definition — this is a build-skew bug, never retried.
realm_unknownThe server hosts no realm with that id.Fix the realm id, or serve that realm on the DO.
unauthorized_avatar_typeThe avatar’s type isn’t in the realm’s permitted set.Connect as a permitted avatar type.
avatar_unresolvedThe connection’s identity mapped to no avatar (resolveAvatar returned nothing).Ensure the connection carries an authenticated coordinate, or set avatarType.
insufficient_securityThe connection’s negotiated wire level is below the realm’s minimum.Raise the connection’s securityLevel (e.g. encrypted). Fail-closed by design.
unauthorized_coordinateA write targets a path this avatar’s rules forbid.Expected on a rules violation — reflect it in UI; don’t retry blindly.
value_invalidA written value doesn’t match the schema.Fix the value shape; this is a program error.
limits_exceededAn ingress limit was hit (frame bytes / patches / write rate).The client coalescer usually splits automatically; a bare breach means back off.
intent_unknownAn intent name the realm doesn’t define.Fix the intent name (it’s part of the schema hash).
version_gap_unrecoverableThe client’s version is behind the replayable window.Automatic — the client full-rehydrates; no app action.
write_before_hydraterealm.update() ran before the first hydrate (store still {}).await realm.whenLive() first, or use assertOnAttach for state that must exist on attach.
frame_too_staleAn optimistic frame expired before an authoritative answer — an unknown outcome.Re-read state; do not blindly re-issue a non-idempotent intent (it may have committed). Detect with isUnknownOutcomeRejection.
durable_backlog_overflowToo many unconfirmed durability: "reassert" frames (a long outage).Re-sync from your own source of truth after reconnecting.
frame_invalidA malformed/hostile realm frame (fuzz gate).Not app-actionable — the codec dropped it. Investigate a buggy/hostile peer.
write_target_missingA well-formed write whose target’s parent no longer exists (a pruned entry / a transient region reset by a wake).Re-read state; an assertOnAttach re-creates a pruned own-entry. Distinct from frame_invalid.

Raised while opening or maintaining a wire connection (createWireClient / connectChannel).

IdWhat emits itWhat to do
connect_exhaustedEvery transport in the preference chain failed.Check the endpoints/network; the keep-alive ladder retries a duplex link.
connect_closedconnect() on a client already close()d — terminal.Build a new client; a closed one never reconnects.
dial_failedOne transport’s dial or handshake failed (a chain-item detail inside connect_exhausted).Read reason; usually a bad URL or an unreachable host.
dial_unavailableThe carrier has no valid endpoint right now (createRequest returned null).A policy signal, not a failure — the keep-alive loop parks until the next explicit connect()/dispatch.
protocol_unsupportedA protocol frame sent on a connection whose peer never advertised it.Register the protocol before the handshake (dial with the realm/devtools mux attached).
protocol_on_exchange_onlyA prefixed protocol registered on an exchange-only (request/reply) connection.Thrown at bring-up, not connect — a protocol needs a duplex carrier (a realm can’t ride HTTP-exchange alone).
protocol_security_blockedA protocol frame on a non-authenticated connection that didn’t opt into allowPlain.Raise the connection’s security level, or the protocol must opt in (devtools does).
binding_version_mismatchA rehydrated hibernation binding has an unknown schema version.Automatic — the socket is treated as fresh and re-handshakes.
identity_pin_mismatchThe peer rejected the handshake: this client’s verify key ≠ the one pinned for its identity (TOFU).Permanent for this identity+key pair — the redial loop parks. Recover under a new persistent id, or clear the peer-side pin. Branch with err.hasId("identity_pin_mismatch").

Actions — err_nice_action, err_nice_transport, err_nice_transport_ws

Section titled “Actions — err_nice_action, err_nice_transport, err_nice_transport_ws”

Raised by the action runtime and its transport. Most are program errors (wiring/registration); the validation + reliability ids are the ones a consumer branches on.

err_nice_action — runtime & registration: not_implemented, action_id_not_in_domain, domain_already_exists_in_hierarchy, domain_no_handler, hydration_domain_mismatch, hydration_action_state_mismatch, hydration_action_id_not_found, no_action_execution_handler, wire_action_not_payload, wire_not_action_data, client_runtime_already_registered, client_runtime_not_registered, runtime_reset, no_client_runtimes_registered. The four you’ll branch on: action_input_validation_failed / action_output_validation_failed (a schema check failed — HTTP 400/500; fix the payload) and their *_promise variants (a validator returned a promise, which isn’t supported — make it synchronous).

err_nice_transport — dispatch & reliable delivery: timeout, not_found, unsupported, initialization_failed, send_failed, invalid_action_response, and the reliable-tier trio you branch on — reliable_outbox_overflow (the peer isn’t acknowledging; the send was rejected to bound memory — reconnect/re-sync), reliable_delivery_abandoned (not acked within its deadline; the stream skipped past it), reliable_stream_closed (the stream was closed while a send was unacked).

err_nice_transport_ws — WebSocket carrier: ws_disconnected, ws_create_failed, ws_error (transport-level, usually surfaced through the connection’s reconnect handling).

Validation — err_validation (@nice-code/common-errors)

Section titled “Validation — err_validation (@nice-code/common-errors)”
IdWhat emits itWhat to do
standard_schemaA Standard-Schema validation failed (the /hono adapter, action input/output).HTTP 400 — the message carries the field issues; fix the payload.
  • err.hasId("id") — the primary check; true when the error carries that id anywhere in its domain chain.
  • err_domain.isExact(err) — narrow to a domain (err_realm, err_wire_connect, …) before reading its ids, re-exported from the owning package (err_realm + isUnknownOutcomeRejection from @nice-code/realm).
  • isUnknownOutcomeRejection(rejection) — the realm helper for the one case that is genuinely ambiguous (frame_too_stale): treat it as “outcome unknown, re-read”, never as a definite reject.