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.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.
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 code | Meaning | Source |
|---|---|---|
0 | success | request returned 2xx |
3 | unauthorized | HTTP 401 / 403 |
4 | not found | HTTP 404 |
5 | bad request | HTTP 400 |
6 | conflict | HTTP 409 (e.g. duplicate externalId with a different body) |
7 | rate limited | HTTP 429 |
8 | server error | HTTP 5xx |
1 | other | non-API error (network, file I/O, malformed flag) |
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:codeis a stable error-code slug (AMOUNT_BELOW_MIN,WITHDRAWAL_LIMIT_EXCEEDED,INVALID_KEY, …). Branch on this in scripts; not on the human message.traceis the correlation ID. The Bron team can pull the exact ES log line for your call with this. Quote it when reporting issues.detailsis the unstructured payload — depends on the error code. The shape is documented in theErrorspage.
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: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.code | Typical cause |
|---|---|
INVALID_KEY / KEY_REVOKED | API key not registered, or kid was revoked |
INSUFFICIENT_BALANCE | Withdrawal amount exceeds the account balance |
AMOUNT_BELOW_MIN | Amount under the network’s documented minimum |
EXTERNAL_ID_CONFLICT | An externalId is being reused with a different body |
INVALID_ADDRESS / ADDRESS_NOT_WHITELISTED | Destination not on the workspace allow-list |
RATE_LIMITED | You’ve hit the per-key/per-workspace rate limit; back off |
WORKSPACE_NOT_FOUND | --workspace doesn’t match the registered key |
Idempotency contract
Everytx <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 code0. - Same
externalId, different body → exit code6(conflict),code: EXTERNAL_ID_CONFLICT. - Without
externalId→ every retry is a brand-new transaction. Don’t do this on transaction-creation calls.
--externalId from something stable (task ID, request hash, timestamp + nonce); keep it in scope across retries.
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):- Re-run with
--debugto capture envelope + ping + dial logs to stderr. - Note the
trace:value from the error envelope. - File the issue at https://github.com/bronlabs/bron-cli/issues with: command (redact secrets), CLI version (
bron --version), error envelope,trace,--debuglog if relevant.
