Skip to content

Errors

Every error carries a stable machine-readable code plus a human-readable message. Codes never change meaning; messages may be reworded. Both official SDKs surface the code (Error::Api { code, .. } in Rust, BlinkApiError.code in TypeScript).

REST

Errors return a JSON envelope with an HTTP status:

json
{ "code": "NOT_FOUND", "error": "market 99999 not found" }
CodeStatusMeaning
INVALID_PARAMETER400A parameter is missing or invalid (interval, market_type, status, empty q, malformed cursor). The message names the parameter and the accepted values.
NOT_FOUND404Resource does not exist: unknown market, account, subaccount, token, client order id, or transaction hash.
INTERNAL_ERROR500Internal error. Safe to retry with backoff.

Successful responses are always 200 with the documented shape; list endpoints return [] rather than 404 when the account or market simply has no data yet.

WebSocket

Protocol errors arrive as error frames on the open connection:

json
{ "type": "error", "code": "UNKNOWN_CHANNEL", "error": "unknown channel `bogus`" }
CodeMeaningConnection
INVALID_MESSAGEFrame was not valid protocol JSON.stays open
UNKNOWN_CHANNELSubscription named a channel that does not exist.stays open
INVALID_SUBSCRIPTIONMissing a required field (market_id, interval, address/subaccount_id), or sets a field the channel's messages never carry — e.g. is_perps on mark_price (matching is exact per set field, so an inapplicable field would otherwise silently match nothing).stays open
CONNECTION_LAGGEDThe connection fell behind and buffered messages were dropped; deltas cannot be replayed.closed — reconnect and re-subscribe (see lag handling)
FEED_UNAVAILABLEThis deployment does not serve the streaming feed.closed

Transaction submission

Two distinct failure surfaces exist, and only one of them is on-chain:

1. Rejected at admission (the common case). The sequencer pre-executes every transaction before sequencing it. A transaction that would fail — insufficient margin, bad nonce, invalid signature, an order outside the price band — is rejected synchronously and never reaches a block. The submission response carries the failure, e.g.:

Transaction rejected: Transaction execution unsuccessful

Rejected transactions do not consume a nonce and are not indexed; GET /transactions/{hash} returns 404 for them. Retrying after fixing the cause is safe.

2. Sequenced but reverted (rare). Transactions that bypass sequencer admission — forced inclusion via the data-availability layer — execute in a block and can revert there. These ARE indexed, with status: "failed" and the receipt's reason in error:

json
{ "hash": "0x…", "status": "failed", "error": "insufficient margin",
  "block": "1346", "success": false, "timestamp_ms": 1717000000000 }

So in the transaction resource, committed and failed both mean sequenced; admission rejections surface only in the submit response.

Nonce races

Concurrent submissions from one account can lose a nonce race and come back as an admission rejection. Because rejected transactions never sequence, resubmitting with the same payload is safe and is what the official clients do.