# Errors
URL: /docs/api/errors

Error types the New Theory inference API emits, grouped by WebSocket close code.



Every abnormal WebSocket close includes a JSON payload (the error envelope) with six fields.

```json
{
  "code": 4001,
  "type": "auth.invalid_key",
  "message": "API key rejected. The key was revoked, never issued, or malformed. Generate a new key in the New Theory console.",
  "context": { "key_prefix": "nt_a1b2c3d4" },
  "docs": "https://docs.newtheory.ai/api/errors",
  "trace_id": "tr_a1b2c3d4"
}
```

| Field      | Type           | Notes                                                                                    |
| ---------- | -------------- | ---------------------------------------------------------------------------------------- |
| `code`     | `integer`      | WebSocket close code. One of `4001`, `4403`, `4400`, `4404`, `4422`, `4500`, `4503`.     |
| `type`     | `string`       | Dot-namespaced subtype (`domain.specific`). Stable identifier for programmatic handling. |
| `message`  | `string`       | Human-readable description. Do not parse; use `type` for branching.                      |
| `context`  | `object`       | Structured diagnostics. Fields vary by `type` — see each entry below.                    |
| `docs`     | `string` (URI) | Link to this page's anchor for the error type.                                           |
| `trace_id` | `string`       | Opaque support token (`tr_xxxxxxxx`). Include in support requests.                       |

In the Python SDK, every close triggers an exception that inherits from `newt.NewTheoryError`. Catch by class for domain-level handling, branch on `exc.type` for specific cases.

```python
import newt

try:
    robot.run("pick up the cup")
except newt.AuthError as e:
    print(e.type, e.trace_id)          # "auth.invalid_key", "tr_a1b2c3d4"
except newt.NewTheoryError as e:
    print(e.code, e.type, e.message)
```

Every error the server can emit is registered in a single-source catalog, and server startup validates coverage — a new error type can't ship without an entry.

***

## Raised before connection [#raised-before-connection]

These conditions are detected by the SDK during `Robot()` construction, before any WebSocket is opened.

### `RegistryUnavailable` [#registryunavailable]

The registry service (`nt-registry-production.up.railway.app`) was unreachable when `Robot()` tried to resolve the model and contract. This is the only condition that raises `RegistryUnavailable` — it means the registry itself is down or the host cannot reach it, not a model or auth problem.

**Next step:** check your network, verify `NT_BOOTSTRAP_URL` is not set to a bad value (leave it unset to use the production registry), and retry. If the registry is down, wait and retry — it is an always-on service and outages are brief.

### `AuthError` at construction [#autherror-at-construction]

Your API key failed validation at the registry during `Robot()` construction — the registry returned a 401 with a hint that valid keys start with `nt_`. The connection closes before any WebSocket is opened.

**Next step:** re-export `NT_API_KEY` with the correct key (`nt_` prefix + 40 hex chars), or generate a new key in the [console](/docs/authentication).

### `ColdStartRetry` warning [#coldstartretry-warning]

Not an error — a `logging.WARNING` the SDK emits when the GPU container did not respond within the initial connection timeout and the SDK is opening an extended retry (180s). This is the normal cold-start signal. Wait it out; a cold container can take a few minutes to come up. If the extended retry also times out, a `TimeoutError` is raised to your code.

***

## 4001 — Authentication [#4001--authentication]

Sent when the API key fails verification at the WebSocket handshake. The connection closes before any inference runs.

### auth.invalid\_key [#authinvalid_key]

**SDK exception:** `newt.AuthError`

The submitted key was revoked, never issued, or malformed.

```json
{
  "code": 4001,
  "type": "auth.invalid_key",
  "message": "API key rejected. The key was revoked, never issued, or malformed. Generate a new key in the New Theory console.",
  "context": {
    "key_prefix": "nt_a1b2c3d4"
  },
  "trace_id": "tr_a1b2c3d4"
}
```

`context.key_prefix` is the first eight characters of the submitted key — enough for diagnostics without leaking the full value.

**Next step:** generate a new key in the [console](/docs/authentication). If the key was just created, confirm it has not been revoked.

***

## 4403 — Authorization [#4403--authorization]

Sent when the API key is valid but does not own the requested model. A fine-tune belongs to the team that made it — another team's key can't serve it. The connection closes before any inference runs.

### auth.forbidden [#authforbidden]

**SDK exception:** `newt.ForbiddenError`

```json
{
  "code": 4403,
  "type": "auth.forbidden",
  "message": "That model belongs to another team. Your key can only serve models your team owns.",
  "context": {
    "model": "ft_6341c5_d13da9"
  },
  "trace_id": "tr_a1b2c3d4"
}
```

`context.model` is the requested model identifier, as submitted.

**Next step:** use one of your own team's models, or ask the owning team to share. A model's owner is the team that fine-tuned it.

***

## 4400 — Protocol [#4400--protocol]

Sent when a received frame cannot be decoded or is structurally invalid. The connection closes on the first bad frame. The Python SDK raises `newt.ProtocolError` for all 4400 subtypes.

### protocol.malformed\_msgpack [#protocolmalformed_msgpack]

**SDK exception:** `newt.ProtocolError`

A binary WebSocket frame could not be decoded as msgpack.

```json
{
  "code": 4400,
  "type": "protocol.malformed_msgpack",
  "message": "The server received a WebSocket frame that could not be decoded as msgpack. Ensure every frame is msgpack-encoded binary.",
  "context": {
    "frame_bytes": 42
  },
  "trace_id": "tr_a1b2c3d4"
}
```

`context.frame_bytes` is the size of the frame that failed to decode.

**Next step:** use `msgpack.packb(obs, use_bin_type=True)` to encode each frame. Text WebSocket frames are not accepted.

### protocol.missing\_type [#protocolmissing_type]

**SDK exception:** `newt.ProtocolError`

A decoded msgpack frame did not contain the required `type` key.

```json
{
  "code": 4400,
  "type": "protocol.missing_type",
  "message": "The server received a msgpack frame with no 'type' key. Every frame must include a 'type' key set to 'obs' or 'stop'.",
  "context": {
    "keys_present": ["state", "images"]
  },
  "trace_id": "tr_a1b2c3d4"
}
```

`context.keys_present` lists the keys the server found in the frame.

**Next step:** ensure every frame dict includes a `"type"` key before packing.

### protocol.unknown\_type [#protocolunknown_type]

**SDK exception:** `newt.ProtocolError`

A decoded msgpack frame had a `type` value the server does not recognize.

```json
{
  "code": 4400,
  "type": "protocol.unknown_type",
  "message": "The server received a frame with an unrecognized type. Accepted frame types are: 'obs', 'stop'.",
  "context": {
    "received_type": "observation"
  },
  "trace_id": "tr_a1b2c3d4"
}
```

`context.received_type` is the value the server received.

**Next step:** `type` must be exactly `"obs"` (to send an observation) or `"stop"` (to end the session).

***

## 4404 — Model not found [#4404--model-not-found]

Sent when the model identifier in the first `obs` frame does not match any UID or tag in the server's registry.

### model\_not\_found.unknown\_identifier [#model_not_foundunknown_identifier]

**SDK exception:** `newt.ModelNotFoundError`

```json
{
  "code": 4404,
  "type": "model_not_found.unknown_identifier",
  "message": "Model not found. Check spelling or call newt.list_models() to see available models.",
  "context": {
    "requested": "so101-v2",
    "known_uids": ["ft_base_molmoact2", "ft_6341c5_d13da9"],
    "known_tags": ["so101"]
  },
  "trace_id": "tr_a1b2c3d4"
}
```

`context.requested` is the identifier from the `obs` frame. `context.known_uids` and `context.known_tags` list what the registry contained at the time.

**Next step:** model identifiers are case-sensitive. Run `newt.list_models()` to see current UIDs and tags.

***

## 4422 — Contract mismatch [#4422--contract-mismatch]

Sent when an `obs` frame's data does not match the model's trained input contract. Each subtype names the specific field that failed validation. The Python SDK raises `newt.ContractMismatchError` for all 4422 subtypes.

### contract\_mismatch.state\_shape [#contract_mismatchstate_shape]

**SDK exception:** `newt.ContractMismatchError`

The state array shape does not match the shape the model was trained on.

```json
{
  "code": 4422,
  "type": "contract_mismatch.state_shape",
  "message": "State shape mismatch. Adjust read_state() to return the expected shape, or switch to a model that matches your robot.",
  "context": {
    "model": "so101",
    "expected_shape": [6],
    "got_shape": [14]
  },
  "trace_id": "tr_a1b2c3d4"
}
```

**Next step:** check the model's expected state shape via `robot.contract`. The contract is fixed at training time.

### contract\_mismatch.state\_dtype [#contract_mismatchstate_dtype]

**SDK exception:** `newt.ContractMismatchError`

The state array dtype does not match the dtype the model was trained on.

```json
{
  "code": 4422,
  "type": "contract_mismatch.state_dtype",
  "message": "State dtype mismatch. Cast your state array to the expected dtype in read_state().",
  "context": {
    "model": "so101",
    "expected_dtype": "float32",
    "got_dtype": "float64"
  },
  "trace_id": "tr_a1b2c3d4"
}
```

**Next step:** most models expect `float32`. Use `state.astype(np.float32)` in `read_state()`.

### contract\_mismatch.camera\_missing [#contract_mismatchcamera_missing]

**SDK exception:** `newt.ContractMismatchError`

A camera the model requires was absent from the `obs` frame's `images` dict.

```json
{
  "code": 4422,
  "type": "contract_mismatch.camera_missing",
  "message": "Required camera missing. Add the missing camera to the images dict in read_state(), or switch to a model that matches your hardware.",
  "context": {
    "model": "so101",
    "missing_required_camera": "side",
    "cameras_required": ["top", "side"],
    "got_cameras": ["top"]
  },
  "trace_id": "tr_a1b2c3d4"
}
```

`context.missing_required_camera` names the absent key. `context.cameras_required` lists all keys the model requires.

**Next step:** check `cameras.required` via `robot.contract`. Each required camera key must appear in the `images` dict.

### contract\_mismatch.image\_shape [#contract_mismatchimage_shape]

**SDK exception:** `newt.ContractMismatchError`

A camera image's shape does not match the shape the model expects.

```json
{
  "code": 4422,
  "type": "contract_mismatch.image_shape",
  "message": "Image shape mismatch. Resize the camera frame to the expected shape (CHW) in read_state().",
  "context": {
    "model": "so101",
    "camera": "top",
    "expected_shape": [3, 224, 224],
    "got_shape": [3, 480, 640]
  },
  "trace_id": "tr_a1b2c3d4"
}
```

**Next step:** images must be in CHW layout. Check the expected shape via `robot.contract` and resize on the client.

***

## 4500 — Server error [#4500--server-error]

Sent when the server encounters an unhandled exception, either inside the model call or in the WebSocket handler itself. The Python SDK raises `newt.ServerError` for all 4500 subtypes. Include `exc.trace_id` in any support request.

### server.inference\_error [#serverinference_error]

**SDK exception:** `newt.ServerError`

The model raised an unhandled exception during `policy.infer()`.

```json
{
  "code": 4500,
  "type": "server.inference_error",
  "message": "The model raised an error during inference. Retry the request. If this persists, contact support with the trace_id.",
  "context": {
    "error_type": "RuntimeError"
  },
  "trace_id": "tr_a1b2c3d4"
}
```

`context.error_type` is the Python exception class name from the inference call.

**Next step:** retry the request. If this persists, contact support with the `trace_id`. This error may indicate an edge case in the input data.

<Callout type="info">
  In an earlier protocol revision, in-model errors emitted a terminal frame with stop\_reason="error" and closed with code 1000. They now close 4500 with this envelope, so ServerError is raised rather than returning a RunResult with stop\_reason="error".
</Callout>

### server.internal [#serverinternal]

**SDK exception:** `newt.ServerError`

An unhandled exception occurred in the WebSocket handler outside the inference path.

```json
{
  "code": 4500,
  "type": "server.internal",
  "message": "The server encountered an internal error and closed the session. Retry the request. If this persists, contact support with the trace_id.",
  "context": {
    "error_type": "ValueError"
  },
  "trace_id": "tr_a1b2c3d4"
}
```

**Next step:** retry the request. If this persists, contact support with the `trace_id`.

***

## Embodiment [#embodiment]

Raised by the SDK during `Robot()` construction when the value passed to `embodiment=` is invalid. This is a client-side check — no WebSocket is opened, and no server is involved. The SDK raises `newt.EmbodimentError` for all three subtypes; the `code` is `4422` by HTTP convention. See the [SDK reference](/docs/newt-sdk#embodiment) for the protocol an embodiment object must satisfy.

### embodiment.string\_not\_object [#embodimentstring_not_object]

**SDK exception:** `newt.EmbodimentError`

Raised when `embodiment=` receives a string. `embodiment=` takes your embodiment object, not a name string — the SDK never resolves names. This commonly happens when a developer expects a name-based API such as `Robot(embodiment="so101")`.

```json
{
  "code": 4422,
  "type": "embodiment.string_not_object",
  "message": "Robot(embodiment=) takes your embodiment object, not a name string (got 'so101'). Generate one with a starter kit, or implement read_state() and execute() on any class.",
  "context": { "got": "so101" }
}
```

`context.got` is the string the SDK received.

**Next step:** pass an object that implements `read_state()` and `execute()`. Generate one with a [starter kit](/docs/starters), or write your own class — see [Set up your embodiment](/docs/set-up-your-embodiment).

### embodiment.conflict [#embodimentconflict]

**SDK exception:** `newt.EmbodimentError`

Raised when `embodiment=` is combined with `read_state=` or `execute=`. The two paths are equivalent and mutually exclusive: `embodiment=` is convenience shorthand for passing the two callbacks separately.

```json
{
  "code": 4422,
  "type": "embodiment.conflict",
  "message": "Robot() received both embodiment= and read_state=. Pick one path: pass embodiment= (an object with read_state() and execute()), or pass read_state= and execute= as separate callbacks. The two paths are equivalent; embodiment= is convenience shorthand.",
  "context": { "conflict_kwargs": ["read_state="] }
}
```

`context.conflict_kwargs` lists the conflicting callback arguments the SDK saw.

**Next step:** pass `embodiment=` alone, or pass `read_state=` and `execute=` alone. Not both.

### embodiment.missing\_method [#embodimentmissing_method]

**SDK exception:** `newt.EmbodimentError`

Raised when the object passed as `embodiment=` is missing `read_state()`, `execute()`, or both. The message names every missing method.

```json
{
  "code": 4422,
  "type": "embodiment.missing_method",
  "message": "The object passed as embodiment= is missing: execute(). An embodiment must implement both read_state() -> dict and execute(action_chunk) -> None.",
  "context": { "missing": ["execute()"], "got_type": "PartialRig" }
}
```

`context.missing` lists the absent methods; `context.got_type` is the class name of the object that was passed.

**Next step:** implement both `read_state() -> dict` and `execute(action_chunk) -> None` on the class. Any object with those two methods is an embodiment — no inheritance or registration required.

***

## 4503 — Verifier unavailable [#4503--verifier-unavailable]

Sent when the key verification service is unreachable or returns an error during the WebSocket handshake. The connection closes before any inference runs.

### verifier.unavailable [#verifierunavailable]

**SDK exception:** `newt.VerifierError`

```json
{
  "code": 4503,
  "type": "verifier.unavailable",
  "message": "The API key verification service is temporarily unavailable. Retry the request in a few seconds.",
  "context": {
    "error_type": "httpx.ConnectTimeout"
  },
  "trace_id": "tr_a1b2c3d4"
}
```

`context.error_type` is the Python exception class from the verification call.

**Next step:** this is a server-side infrastructure issue, not a problem with your API key. Retry with exponential backoff.
