# Exit codes and errors

> What div exits with, what it prints when something goes wrong, and the one line it adds about what to do next.

A shell script or an agent should be able to branch on `div` without parsing anything. So the exit code carries the answer, and the words on stderr are for whoever has to fix it.

## Exit codes

| Code | When |
| --- | --- |
| the run's own | `div run` attached, and `div logs`, when the run has finished |
| `0` | it worked — or you detached, and the run is still going. `div stop` exits 0 when the run had already finished, too |
| `1` | the API refused, or could not be reached |
| `2` | the command was typed wrong, or there is no key |

A run that exits 3 makes `div run` exit 3. A run that did not succeed but has no exit code of its own — stopped at its ceiling, stopped at the org's limit, canceled — makes `div` exit 1. A [check](https://docs.divergentlabs.xyz/compute/cli/run.md#checks) the run's result missed changes none of this: the exit code is the run's, and the verdict is the experiment's.

[`div result`](https://docs.divergentlabs.xyz/compute/cli/result.md) exits 1 when there is no result to print: the run has not finished, wrote none, or has nothing at the path asked for.

## Typed wrong

A command typed wrong exits 2 and names what was wrong:

```text
div run has no --max-spent
--max-spend has to be a number, not five
--env takes KEY=value, not DEBUG
--check takes a path, a comparison and a value, like metrics.accuracy>=0.8, not accuracy
--gpus has to be a whole number, not 2.5
--status is one of active, queued, provisioning, running, succeeded, failed, canceled, budget_exceeded, limit_reached, not done
there is no div deploy
```

An unknown flag is an error rather than a silently ignored typo.

## Refused by the API

When the API refuses, `div` prints the message the API sent and exits 1. For the codes worth acting on, it adds one line about what to do next:

| The API said | The line after it |
| --- | --- |
| `insufficient_credit` (`402`) | `top up at divergentlabs.xyz/billing, or turn on auto top-up there, then place it again` |
| `usage_limit_reached` (`402`) | `the org's usage limit is set at divergentlabs.xyz/billing: raise it there, or wait for the period to end` |
| the key was not accepted (`401`) | `run div login, or check DIVERGENT_API_KEY — keys start with dv_live_` |
| `quota_exceeded`, `container_quota_exceeded` | `stop a run with div stop, or pause an endpoint, or move to Compute Pro at divergentlabs.xyz/plan` |
| `storage_full` | `delete files from the Storage page at divergentlabs.xyz/storage, or move to Compute Pro at divergentlabs.xyz/plan` |
| `unknown_sku` | `try one of: b300, cpu, h100, h200. div catalog has their prices` |
| `secret_not_found` | `div secrets lists the ones the org has` |
| `insufficient_scope`, for `secrets:` | `this key was made before secrets: run div login again for one that can, or give a key both secrets scopes under Settings` |
| `supplier_unreachable` (`502`) | `the hardware behind the API did not answer, and nothing typed was wrong: try it again` |
| anything else over `500` | `the API failed on its side, not on what was typed. Try it again — after div run, check div runs first` |

On Compute Pro, the quota and storage lines end `or ask us for more` instead: there is no bigger plan to move to.

A `500` says nothing about whether a run was written before the failure, which is why `div runs` comes before placing it again.

## Limits

What an org can hold at once is its plan's, and `div` is told which one it hit. [`div limits`](https://docs.divergentlabs.xyz/compute/cli/limits.md) shows how close it is to each:

| | Free | Compute Pro |
| --- | --- | --- |
| GPUs held | 2 | 25 |
| containers held | 10 | 250 |
| storage, as last measured | 50 GB | 1 TB |

A run holds one container and its GPUs; a CPU run holds a container and no GPU. Endpoint replicas count the same way, so an endpoint sitting idle is still holding what it holds. Storage is held against what the volumes last measured, every fifteen minutes or after a write, so the org can go over by what it writes between two measurements — and is refused after that.

An org can also set a limit on what it spends in a period, in the dashboard. When it is reached, runs already going stop within a minute with the status `limit_reached`, and new ones are refused with `usage_limit_reached`. The same happens when the org runs out of credit and has no card that will top it up.

A request with invalid fields gets one indented line per field, naming it and what was wrong with it.

When the API cannot be reached at all, `div` says `could not reach` and the URL it tried, and exits 1. `div whoami` shows which URL that is and where it came from. [`div papers`](https://docs.divergentlabs.xyz/compute/cli/papers.md) asks arXiv instead, so its `could not reach` names `https://export.arxiv.org`.

## Help

```bash
div --help           # every command
div run --help       # what one command takes
div --version
```

`div` with no command prints the same list as `--help` and exits 1.
