Skip to main content

Documentation Index

Fetch the complete documentation index at: https://developer.bron.org/llms.txt

Use this file to discover all available pages before exploring further.

Every CLI invocation that fails surfaces three things: a stable exit code, a structured error envelope on stderr, and a trace ID you can quote when reporting the issue.

Exit codes

The CLI maps HTTP status to a small set of stable exit codes. Conditional shell logic (bron tx get $id || handle "$?") and CI gating both rely on these.
Exit codeMeaningSource
0successrequest returned 2xx
3unauthorizedHTTP 401 / 403
4not foundHTTP 404
5bad requestHTTP 400
6conflictHTTP 409 (e.g. duplicate externalId with a different body)
7rate limitedHTTP 429
8server errorHTTP 5xx
1othernon-API error (network, file I/O, malformed flag)
These won’t shift across 0.x. New status codes get a new mapping; existing mappings stay put.

Error envelope

A 4xx / 5xx response prints to stderr in this shape:
Error: <human-readable message>
  code:    <error-code-slug>
  trace:   <correlation-id>
  details: <JSON object | flat key=value list>
Concrete example — a withdrawal with a too-low amount:
Error: Amount is below the network minimum
  code:    AMOUNT_BELOW_MIN
  trace:   sdk-a19eef801c5d88d789b7b13e764ddb99
  details: {"min":"0.0001","provided":"0.00001","assetId":"5000","networkId":"ETH"}
  • code is a stable error-code slug (AMOUNT_BELOW_MIN, WITHDRAWAL_LIMIT_EXCEEDED, INVALID_KEY, …). Branch on this in scripts; not on the human message.
  • trace is the correlation ID. The Bron team can pull the exact ES log line for your call with this. Quote it when reporting issues.
  • details is the unstructured payload — depends on the error code. The shape is documented in the Errors page.
The CLI sanitises ANSI escape sequences out of error output, so it’s safe to redirect stderr to a log file.

Why a trace ID matters

The frontend calls this the Error ID. Same value: it’s the per-request correlation ID generated server-side, attached to every log line for that request across every service it touches (public-api, the worker that picked it up, MPC signers, blockchain writer). Quoting it lets us reproduce the failure exactly:
# In a bug report, paste this:
trace: sdk-a19eef801c5d88d789b7b13e764ddb99
If you’re integrating Bron into a larger system, log this trace alongside whatever request ID you generate yourself — when something goes wrong, the join across logs is trivial.

Common error codes

A small reference of the most-seen codes; the canonical list is on Errors.
codeTypical cause
INVALID_KEY / KEY_REVOKEDAPI key not registered, or kid was revoked
INSUFFICIENT_BALANCEWithdrawal amount exceeds the account balance
AMOUNT_BELOW_MINAmount under the network’s documented minimum
EXTERNAL_ID_CONFLICTAn externalId is being reused with a different body
INVALID_ADDRESS / ADDRESS_NOT_WHITELISTEDDestination not on the workspace allow-list
RATE_LIMITEDYou’ve hit the per-key/per-workspace rate limit; back off
WORKSPACE_NOT_FOUND--workspace doesn’t match the registered key

Idempotency contract

Every tx <type> / tx create call accepts --externalId <key>. Bron de-duplicates by (workspaceId, externalId):
  • Same externalId, same body → returns the previously-created transaction. No duplicate. Exit code 0.
  • Same externalId, different body → exit code 6 (conflict), code: EXTERNAL_ID_CONFLICT.
  • Without externalId → every retry is a brand-new transaction. Don’t do this on transaction-creation calls.
For shell pipelines or agent flows that retry on perceived failure, this is the only safe path. Generate --externalId from something stable (task ID, request hash, timestamp + nonce); keep it in scope across retries.
EXTID="payout-$(date +%Y%m%d)-$(openssl rand -hex 4)"

# Retry-safe — third attempt returns the same tx as the first.
for i in 1 2 3; do
  bron tx withdrawal --externalId "$EXTID" --accountId <a> --params.amount=100 ... \
    && break
  sleep 5
done

Retry strategy

The CLI itself retries idempotent reads (GET) on transient 5xx with linear backoff up to 3 attempts; you don’t have to wrap reads in a retry loop. Writes are not retried automatically — that’s the caller’s responsibility (with --externalId so retries are safe). If you hit 429 (RATE_LIMITED), respect the Retry-After header in the response. The CLI prints it as details.retryAfter.

Reporting an issue

When the error isn’t obviously self-inflicted (config / bad input):
  1. Re-run with --debug to capture envelope + ping + dial logs to stderr.
  2. Note the trace: value from the error envelope.
  3. File the issue at https://github.com/bronlabs/bron-cli/issues with: command (redact secrets), CLI version (bron --version), error envelope, trace, --debug log if relevant.
Inside Bron, that trace is enough to pull the exact ES log entries for the call across every service it touched.