Errors and exit codes
Every failure has a stable code you can branch on: an error code when the API refuses a call, a failure.kind when a run starts and then fails, and an exit code from the CLI. This page lists all three and says which to retry. If the CLI does something this page does not explain, open an issue on GitHub.
CLI exit codes
Each outcome has a fixed exit code, so a script or a coding agent can decide what to do without reading the text.
Exit | Means | What to do |
|---|---|---|
0 | It worked. Also a run started with | Carry on |
1 | The script is invalid. Each finding prints as | Fix the lines named, then run |
2 | The run started and failed. The failure kind and message are printed | Look up the kind below |
3 | Not signed in, the key lacks a scope, or a plan limit | Sign in, use a key with the scope, or upgrade |
4 | Bad usage: a wrong flag or value, a missing file, something not found, or a conflict to resolve | Fix the command |
5 | Retryable: busy, rate limited, data not ready, a run not finished yet, a server error or the network | Wait, then run the same command again |
$ chartnaut validate indicators/orb-range
main.ts:14: error: Cannot find name 'rangeHigh'
invalid: orb-range (indicator)
$ echo $?
1
$ chartnaut logout
Signed out.
$ chartnaut runs
error: unauthorized: not logged in. Run `chartnaut login` or set CHARTNAUT_TOKEN.
$ echo $?
3With --on BTC,ETH the CLI runs each instrument and exits with the highest code among them. With --json it also prints the error body on stdout.
Before exiting 5 on busy, rate_limited, a 503 or a network failure, the CLI has already retried: for up to 3 minutes when starting a run, 3 times for everything else. Limits covers how long it waits.
Error codes
The API answers a refused call with {"error": {"code", "message", "details"}}. Branch on code; the message is for people and can change.
Code | HTTP | Means | Retry? | Exit |
|---|---|---|---|---|
| 401 | No key, or it is wrong, expired or revoked. The message says which | No. Sign in again or make a new key | 3 |
| 403 | The key lacks the scope this call needs | No. Use a key with the scope | 3 |
| 403 | The account is on Free, or the call would pass a plan cap, such as your definitions limit | No. Upgrade, or free up room | 3 |
| 403 | The account is on the waitlist, or you cannot change this script | No | 3 |
| 404 | No script, version, run or docs topic by that name. With | No. Check the name, or run it again | 4 |
| 400 | A bad body or parameter; the message names it. | No. Fix the request | 4 |
| 400 | No instrument matches the symbol. | No. Look it up with | 4 |
| 400 | The timeframe is not one of | No | 4 |
| 400 | The window ends before the history your plan reaches | No. Move the window later | 4 |
| 422 | The script does not lint, link or derive. Nothing was saved or run; | No. Fix it | 1 |
| 409 | A newer version was saved since yours. | No. Pull, re-apply, save. See Saving and versions | 4 |
| 409 | The slug is taken, or one of your studies shares a slug with another of your scripts. Add | No | 4 |
| 409 | You asked for the results of a run that is still going, or that failed or was cancelled | Only while it is still going: poll the run | 5 |
| 429 | Past your requests a minute, too many failed key checks from your IP, or too many sign-in starts | Yes, after | 5 |
| 429 or 503 | Past your heavy calls at once, your run queue is full, or a service is briefly unavailable | Yes, after | 5 |
| 500 or 502 | Something broke on Chartnaut's side | Yes. If it keeps happening, write to [email protected] | 5 |
| 501 | The webhooks endpoints, not built yet | No | 5 |
Browser sign-in has four more codes, on POST /auth/token: authorization_pending, slow_down, access_denied and expired_token. The CLI handles them; Poll a sign-in says what each means.
An AI app connected over MCP gets these same codes inside a tool's result, as text starting Error <code>:. Troubleshooting MCP says what to do about each one there.
run_not_finished and not_implemented exit 5 because the CLI treats them as retryable. Retrying not_implemented does not help.
Run failures
A run that started and then failed has status: "failed" and a failure:
{
"status": "failed",
"failure": {
"kind": "out_of_coverage",
"message": "…",
"retryable": false
}
}retryable says whether running it again can help. Trust it over the table when they disagree.
Kind | Means | Retryable | Exit |
|---|---|---|---|
| The script threw or produced nothing. The message and | No. Fix the script | 2 |
| A plan cap stopped it, such as your events budget while a study runs its definitions | No | 3 |
| No data for that instrument, timeframe and window | No | 2 |
| The market data is not available yet, or a study's definition could not run over history | Usually. Check | 5 |
| It ran past its time limit | Yes, on a shorter window | 5 |
| Every one of your runs at once stayed taken | Yes, when a run finishes | 5 |
| Someone cancelled it | Only if you meant to run it | 2 |
| Chartnaut failed, for example a restart during the run | Yes | 5 |
A run that succeeded can still carry errors in its summary. Those are runtime errors on some bars; the run finished and its results are there to read.
For errors inside your script, the troubleshooting table explains each message and how to fix it.
