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

# Errors

> One error shape, and what each status code actually means here.

Every failure returns a JSON body with a `detail` field and an HTTP status that says what kind of
failure it was.

```json theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
{ "detail": "Insufficient quota: requested 8 GPUs, 2 available" }
```

`detail` is a string in almost every case. Request validation is the exception: FastAPI returns an
array, one entry per field it rejected.

```json theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
{
  "detail": [
    {
      "loc": ["body", "spec", "resources", "pools"],
      "msg": "List should have at least 1 item after validation",
      "type": "too_short"
    }
  ]
}
```

A client that renders errors should handle both. `loc` is the path to the offending field, joined
with dots, and `msg` is the message worth showing.

## Status codes

| Code  | What it means here                                                                                                                               | What to do                                                                      |
| ----- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------- |
| `400` | The request was understood and refused. The most common failure by far: a malformed JobSpec, a bad reference, a value outside its declared range | Read `detail`; it names the specific thing                                      |
| `401` | No token, a malformed one, or an expired one                                                                                                     | [Re-authenticate](/en/api-reference/authentication). Never retry the same token |
| `403` | Authenticated, but not allowed. An admin-only endpoint, a dataset you may not read, a deployment you do not own                                  | Not retryable. Ask an administrator                                             |
| `404` | No such job, run, dataset, model, or deployment — or one you are not permitted to know exists                                                    | Check the id                                                                    |
| `409` | A state conflict: promoting a revision that is not ready, pushing a dataset version that already exists, stopping a job that already stopped     | Re-read the current state and decide again                                      |
| `411` | A length-required upload arrived without `Content-Length`                                                                                        | Set the header                                                                  |
| `413` | The upload exceeds the deployment's limit, or a submitted archive expands past it                                                                | Shrink the package. `FORGE_MAX_UPLOAD_MB` is the limit                          |
| `422` | Request body failed schema validation                                                                                                            | Fix the fields `detail[].loc` names                                             |
| `429` | Rate limited — login attempts or device-code polls                                                                                               | Back off. Poll the device flow no faster than every five seconds                |
| `500` | A defect in the control plane                                                                                                                    | Retryable once; then report it with the response and the timestamp              |
| `501` | The deployment is not configured for this feature                                                                                                | An administrator has to enable it                                               |
| `502` | A backend the control plane depends on failed: the executor, the object store, an OIDC provider                                                  | Usually transient. Retry with backoff                                           |
| `503` | The control plane is up but deliberately not serving: maintenance mode, or draining for an upgrade                                               | Retry later. `GET /api/version` still answers                                   |

## Reading a rejected submission

`POST /api/jobs` refuses before anything is scheduled, and the `detail` names the gate that refused
it. These are the ones worth recognising:

<AccordionGroup>
  <Accordion title="Recipe handshake failure" icon="git-compare-arrows">
    The `recipe.lock.json` in your submission does not match the catalog on this server — the name,
    version, digest, or `framework.runtime_id` differs. The platform published a new recipe version
    and your experiment is still pinned to the old one.

    `sf recipe status <exp>` shows the difference; `sf recipe upgrade <exp>` applies it.
  </Accordion>

  <Accordion title="Insufficient quota" icon="cpu">
    The requested GPU count exceeds what your account may hold at once. **Waiting in the queue is not
    this error** — a queued job was admitted. This is a refusal at the door, and only an administrator
    can change it.
  </Accordion>

  <Accordion title="Image registry not allowlisted" icon="container">
    `--image` points at a registry host the deployment does not permit. The allowlist is server-side
    on purpose: it is what stops a submission from running arbitrary code from anywhere.
  </Accordion>

  <Accordion title="Entrypoint override rejected" icon="terminal">
    `spec.source.entrypoint` was non-empty. The recipe owns the entrypoint; a job cannot replace it.
    Use a `custom/custom` recipe if you need to run your own command.
  </Accordion>

  <Accordion title="Sensitive file in the package" icon="shield">
    The packager found `.env`, `*.pem`, `id_rsa*`, or similar and refused to build the archive — this
    fails on your machine, before any request is sent. Secrets reach a job through the platform's
    injection channel, never through the working directory.
  </Accordion>
</AccordionGroup>

<Note>
  Some error strings raised by older code paths are still in Chinese. They are being translated as
  the surrounding code is touched. If you hit one, the status code and the endpoint are the reliable
  parts to quote in a bug report.
</Note>
