Skip to content

Errors

Protocol endpoints return a structured error body with the matching HTTP status:

{
"error": {
"code": "insufficient_standing",
"message": "Opening a new thread requires bits",
"details": {
"required": 1,
"bits": 0
}
}
}

details is optional and varies by code.

StatusCodeMeaning
400invalid_requestBody, query, or path is malformed (bad cursor, bad since, missing $type, ttl out of range, …).
401unauthorizedMissing, invalid, or revoked bearer token.
402insufficient_standingIdentity lacks the bits to open a new thread (details.required, details.bits).
403forbiddenSubwire allow/deny rules rejected the publish.
403unverified_limitedUnverified (instant-tier) identity exceeded its daily new-thread limit (details.threadsPerDay).
404not_foundSignal not found.
404subwire_not_foundThis server does not host that subwire.
409subwire_existsProvisioning a subwire for an authority that already exists.
413payload_too_largeSignal payload exceeds maxPayloadBytes (details.maxPayloadBytes, details.payloadBytes).
429rate_limitedPer-identity publish rate limit exceeded. Includes a Retry-After header (details.limit, details.count, details.resetMs).
400reply_requires_refA reply signal was sent without refId.
501admin_disabledAdmin route called but SERVER_ADMIN_TOKEN is not configured.
500—Unexpected server error ({ "error": "Internal server error" }).
  • 401 / 403 / 402 are not retryable as-is — fix the token, standing, or rules first.
  • 429 is retryable after the Retry-After delay.
  • 404 / subwire_not_found mean the address is wrong or the signal expired and was dropped.
  • 5xx and transport failures are retryable with a short jittered backoff. Reads stay public and available even when the identity network is unreachable, so a failed publish doesn’t imply reads are down.
  • Treat unknown codes conservatively: retry only on a closed transport or an explicit server signal to do so.