Skip to content

Errors ​

Last updated 

Error responses are JSON:

json
{
  "kind": "queue_not_found",
  "message": "queue orders does not exist",
  "details": {"queue": "orders"}
}

kind is present where the status alone is ambiguous; details carries the facts the message states, as fields fixed per kind, and is absent for kinds that have none. Match on the status, kind and details; the message text is for humans and is not part of the contract. A fact never lives only in message: what a client can act on is a field, in the body or in a header. A fact HTTP has a header for is that header and is not repeated in the body: the wait on a 429 is Retry-After, whole seconds.

Statuses without a kind mean what HTTP says: 401 bad credentials, 402 the account is suspended, 403 the key is blocked, 411 a send without Content-Length, 503 the spool is momentarily unavailable — retry.

Kinds ​

Where a kind carries details, its shape follows the meaning — the shape, not a sample: values are the wire types.

KindStatusRetryMeaning
invalid_token400Never.The token — lease or handle — is malformed: a bug or tampering.
dedup_disabled400No — set dedupWindowSeconds or drop the key.The send carries a dedup key but the queue has no dedup window.
unknown_header400No — fix the request.A Spooler-* request header the operation does not define — likely meant for another endpoint.
jsonc
{
  // The refused header's name.
  header: string,
}
retention_limit403No.The requested retention exceeds the plan's limit.
jsonc
{
  // The plan's retention limit.
  maxSeconds: integer,
}
queue_limit403No — delete unused queues.The plan's queue limit is reached.
jsonc
{
  // Queues the plan allows on the spool.
  max: integer,
}
queue_not_found404No.The queue does not exist. A verdict, not lag.
jsonc
{
  // The queue name that was addressed.
  queue: string,
}
spool_not_found404No.No spool of that name on the account. A verdict, like queue_not_found; a spool just created is visible within seconds.
queue_exists409No.A create names a queue that already exists.
queue_deleting409No.The queue refuses the operation while its deletion completes.
queue_busy409Yes.A concurrent settings change lost a race.
not_failed409No — a verdict; the view was fresh.Recover was given a current handle to a message that is not failed.
dedup_in_flight409Yes, after it settles.A send with the same dedup key has not settled yet.
dedup_claimed409No — ack explicitly if folding into it was the intent.An ack-and-send's dedup key is held by another message; nothing was acked.
jsonc
{
  // The message holding the dedup key.
  id: string,
}
stale_token410A lease: receive again. A handle: list again.The token verified but no longer names anything: the lease expired, was settled, or predates a primary change; the message a handle named moved on.
payload_too_large413No.The message exceeds the size limit (see limits).
rate_limited429After the Retry-After seconds.The per-account request rate cap is exceeded (see request rate).
operation_unconfirmed500A send: only on a queue with a dedup window, carrying the same key (see deduplication).The write was accepted but its durability is unknown.
spool_full507After making room.The spool holds its plan's maximum stored messages or payload bytes (see limits).
jsonc
{
  // The stats field the cap is enforced against.
  limit: "messages" | "dataBytes",

  // The cap.
  max: integer,
}

Retrying a send ​

A send is the one operation a retry can duplicate, so its statuses fall in two classes:

  • Appended nothing. Every 4xx, 503 and 507: each is answered before the append is attempted, so retrying one can never duplicate the message, with or without a dedup key. Most are verdicts; the transient ones are 409 dedup_in_flight, 429 and 503. Such a status speaks for this attempt only: it says nothing about an earlier attempt whose response was lost.
  • May have appended. A 500 of any kind, a 502 or 504, or no response at all. operation_unconfirmed says so explicitly — the entry was written but its durability is unknown — and any other 500 is not proven to precede the write. A 502 or 504 means the gateway lost the node serving the spool and cannot tell one that was unreachable from one that went away after committing; a dropped connection or a client timeout is the same from the client's side. Retry these only on a queue with a dedup window, carrying the key the first attempt carried, while the window still remembers it — see deduplication. Without a key, a retry can append twice.

Ack-and-send needs no key to retry in either class: a retry of a committed call fails with 410 and appends nothing.

Settles are safe to retry in the same sense: repeating a committed settle answers 410 and changes nothing. A 410 on the retry does not prove the first attempt succeeded, though — the lease may instead have expired or become stale — so which statuses are worth retrying is the table above, for every operation alike; a 502 or 504 on a settle is the gateway losing the node, and the retry cannot tell the two apart.

A receive changes delivery state, so a retry after a lost response is a second receive: it may lease a different message, while the first delivery stays leased until its lease times out and it is redelivered — or, on a queue with no lease timeout, until a primary change drops it.