> ## Documentation Index
> Fetch the complete documentation index at: https://docs.simforge.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# JSON output, errors and exit codes

> The contract every simforge command keeps - one JSON document on stdout, a structured error on stderr, and exit codes 0, 1 and 2 - so scripts and agents can rely on it.

Every `simforge` command keeps the same contract, so a script or an agent can drive it without parsing prose.

## stdout: one JSON document

A command prints exactly one JSON document on stdout. JSON is the default; `--json` asks for it explicitly, and `--pretty` indents the same document for people. Nothing else is ever written to stdout.

## stderr: a structured error

When a command fails it prints one JSON line on stderr:

```json theme={null}
{"code": "max_cost_required", "reason": "…", "hint": "Pass --max-cost CENTS to explicitly cap this cloud job."}
```

* `code` is stable: key your handling on it. Never parse `reason`, which is for people.
* `hint` says what to do next, often the exact command.
* `path` names the input at fault, and `detail` carries structured context, when there are any.
* `httpStatus` and `requestId` are there when the SimForge host refused a request: quote the `requestId` to support, which traces the request by it.

`login` also writes event lines (`{"event": …}`, never a `code`) on stderr while it waits: the URL and code a person must approve. `runtime install` and `maps pull` write `{"event": "distribution.download.progress", "bytes": {"done": …, "total": …}, "percent": …}` lines as they download, at each tenth of the archive and at least every 30 seconds. A command that waits on a cloud run (`--cloud --wait`, `runs watch`) writes `{"event": "run.progress", "runId": …, "status": …, "jobs": [{"kind", "status", "progress", "queue"}], "elapsedSeconds": …, "message": …}` when it first reads the run, whenever the run or a job changes, and at least every 30 seconds. Saving a scenario file as a hosted revision (the first `--cloud` run or dry run of its content) writes `{"event": "revision.freeze", "draftId": …, "simulation": …, "elapsedSeconds": …, "message": …}` when it starts and each time the host answers that its authoritative simulation (`queued` or `running`) is still going.

## Exit codes

| Exit | Meaning | What to do |
| - | - | - |
| 0 | OK | Read stdout |
| 1 | The command could not run: bad flags, a missing file, the runtime or a map not installed, not signed in | Fix the invocation, or install what the error names |
| 2 | The command ran and found something wrong with its input: a failed check, a refused operation, a digest mismatch | Report or repair the input; retrying the same input gives the same answer |

## The command surface as data

```sh theme={null}
simforge --help
simforge render --help
simforge help --json
```

`simforge --help` prints a compact index: every command with a one-line summary. `simforge <command> --help` prints one command: its arguments and flags with types, allowed values, ranges, defaults, which ones are required or exclude each other, and the global flags it takes. `simforge help --json [command]` prints the full schema of every command, or of one subtree. An unknown flag is an error (`unknown_flag`), except after the scenario of `render`, `simulate` and `preview`, whose trailing arguments are runtime options: check those against the command's help. The same document is published at [/docs/cli.json](https://simforge.ai/docs/cli.json) and rendered as the [command reference](/cli).

A failure on stderr is one `simforge.error/v1` line: `{code, path?, reason, hint, detail?, httpStatus?, requestId?}`. `hint` says what to do next; for an invalid value it quotes the allowed values or range and names the command's `--help`. `detail` carries structured extras only.

A request the hosted API refuses (an HTTP 4xx answer, such as `budget_exceeded` or `insufficient_scope`) exits 2 with the API's own code; a server failure exits 1.

## Common error codes

| Code | Meaning |
| - | - |
| `unknown_command`, `unknown_flag` | Not a command or flag of this CLI; read `--help` |
| `missing_argument`, `bad_value` | A required argument is missing, or a value is invalid |
| `not_logged_in`, `session_invalid` | Sign in with `simforge login` |
| `runtime_not_installed` | Install the runtime: `simforge runtime install --accept-license` |
| `runtime_platform_unsupported` | This platform has no local runtime (Windows on Arm): add `--cloud` |
| `map_not_installed`, `unknown_map` | Pull the map: `simforge maps pull <name>@<version> --for 2d --accept-license` (`--for 3d` for a local 3D render) |
| `map_3d_not_installed` | The map is installed for 2D only: `simforge maps pull <name>@<version> --for 3d`, or render with `--cloud` |
| `runtime_3d_not_installed` | The runtime is installed for 2D only: `simforge runtime install --for 3d --accept-license`, or render with `--cloud` |
| `agreement_acceptance_required` | Read `simforge runtime license`, then pass `--accept-license` |
| `entitlement_required` | This download is not available to your account |
| `entitlement_revoked` | SimForge revoked this account's right to the download; it is not re-granted by accepting again |
| `gpu_unsupported`, `gpu_memory_unsupported`, `gpu_driver_unsupported` | The GPU is outside the [supported range](/install.md#what-the-machine-needs) (NVIDIA with at least 8 GiB and driver 570 or newer, or Apple M3 or newer); 2D renders, simulation and `env serve --no-sensors` still work |
| `native_gpu_out_of_memory` | The scene did not fit in GPU memory: use `--textures bc7-512`, fewer or smaller cameras, or `--cloud` |
| `signature_missing`, `signature_invalid`, `signature_untrusted`, `signature_wrong_host`, `signature_mismatch` | The download is not one SimForge signed for this host; nothing was installed |
| `runtime_install_invalid` | The runtime found is not an installed SimForge runtime release (no `runtime-manifest.json` beside it): run `simforge runtime install --accept-license` |
| `recording_missing` | A scenario that replays a recording cannot find `recordings/<sha256>.rec.json.gz` beside its `document.json` |
| `plan2d_map_missing` | The map's 2D derivative is not installed: pull the map again |
| `max_cost_required`, `budget_exceeded` | A cloud run needs a cost cap, or its estimate is over it |
| `insufficient_credits` | The workspace's credits do not cover a cloud run's [price](/cloud.md#prices) |
| `cloud_not_open` | SimForge Cloud is not open on this host yet, or does not run that work yet (`detail.code` `run_kind_unavailable`): run without `--cloud` |
| `email_unverified` | Downloads and cloud runs need a verified email: open the link in your email, or resend it from the page the hint names |
| `file_exists` | The output exists; pass `--force` to overwrite it |

Codes for a specific area are on its page: [sign-in and runtime](/sign-in.md), [cloud](/cloud.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.