# Error codes and fault states

> Every rt-control reason code (all 153), the numeric native command, jog and grant reasons, execution fault bits with their recovery classes, and axis readiness states.

URL: https://advancedmetalresearch.com/docs/reference/error-codes
Section: RosieOS docs / Reference
Last updated: 2026-10-10

When rt-control refuses a request it returns HTTP 409 (413 for an oversized body, 404 for an unknown resource) with a reason code in `error`. This page lists every reason in the contract, grouped by area, with the operations that can return it. It also covers the numeric reasons inside native receipts, the execution fault bits and the per-axis readiness states in Status.

The reason list is generated from `reasons` in `rt-core/protocol/application-v1.schema.json`, which the contract calls the closed catalogue of adapter-owned labels. The same names are exported as constants by all three clients: `control.Reason…` in Go, `rosie::rt_control::Reason…` in C++ and `Reason…` in TypeScript.

> [!TIP] **Machine-readable.** Every reason on this page, with its meaning, group, HTTP status and the operations that return it, as [JSON](https://advancedmetalresearch.com/docs/data/error-codes.json).

## Reading an error

409 Conflict:

```json
{
  "schema": "rosie.rt-control.response.v1",
  "operation": "start_trajectory",
  "error": "not_ready",
  "native_result": {
    "Sequence": 31,
    "Handle": 7,
    "Generation": 3,
    "Operation": 292,
    "Result": 1,
    "Reason": 2,
    "AxisMask": 511
  }
}
```

- `error` is a catalogue label, or a diagnostic that starts with one (`native_limit_exceeded: segment=2 sample=118 axis=J3`). Some errors are open diagnostics with no label: JSON decoding, I/O, context and native text such as `RTCore rejected operation 0x124: reason 2`. Match on the leading label.
- `native_result` is present when the core refused a command. Read its numeric `Reason` in [native command reasons](https://advancedmetalresearch.com/docs/reference/error-codes#native-command-reasons).
- `native_jog_result` is present when the jog lane refused. Read `StateReason`, `ControlReason` or `UpdateReason` in [native jog reasons](https://advancedmetalresearch.com/docs/reference/error-codes#native-jog-reasons).
- `data.limit_violation` accompanies `native_limit_exceeded` and `native_segment_rate_exceeded` from a program upload. It gives `kind` (`position` or `velocity`), `segment`, `sample`, `axis`, `value`, `limit` and `unit` (`rad` or `rad/s`).

Treat an unknown label, a malformed reply or a transport failure as an unknown outcome. Stop producing motion, send an authenticated `stop` if you can, and reconcile Status before acquiring again.

## rt-control reason codes

All 153 reasons, in 13 groups. **Returned by** links to the operation on the [rt-control HTTP API](https://advancedmetalresearch.com/docs/apis/rt-control-http) page. The meaning is the contract's own text where it gives one, and otherwise a description of the code that raises the reason.

### Request envelope and transport

| Reason | Meaning | Returned by |
|---|---|---|
| `body_too_large` | The request body exceeds the operation's size cap (HTTP 413). | Every `POST /v1/control` operation and `prepare_program` (HTTP 413) |
| `invalid_request_envelope` | The body is not a JSON object, or an envelope key is not a string. | Every `POST /v1/control` operation |
| `duplicate_request_field` | A field appears twice in the request envelope. | Every `POST /v1/control` operation |
| `schema_mismatch` | `schema` is not `rosie.rt-control.request.v1`. | Every `POST /v1/control` operation |
| `unknown_operation` | `operation` is not a POST `/v1/control` operation. | Every `POST /v1/control` operation |
| `unknown_endpoint` | No route for this method and path. | Any unknown method or path. |
| `trailing_request_data` | Data follows the JSON object. | Every `POST /v1/control` operation |
| `request_envelope_changed` | The fully decoded request differs from the admitted envelope prefix. | Every `POST /v1/control` operation |
| `invalid_request_id` | `request_id` is null, not a string, or not 1..64 printable ASCII bytes. | Every `POST /v1/control` operation |
| `request_id_conflict` | The `request_id` was already used in this session with a different payload. | Every `POST /v1/control` operation |
| `capability_unimplemented` | The named target capability is unavailable and performs no operation. | [`halt`](/docs/apis/rt-control-http#halt), [`io_arm`](/docs/apis/rt-control-http#io-arm), [`io_disarm`](/docs/apis/rt-control-http#io-disarm), [`mark_telemetry`](/docs/apis/rt-control-http#mark-telemetry), [`abort`](/docs/apis/rt-control-http#abort), [`readiness`](/docs/apis/rt-control-http#readiness). Also `abort`, `readiness`. |
| `invalid_control_generation` | `X-Control-Generation` is missing or not a decimal uint64. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |

### Authority and session

| Reason | Meaning | Returned by |
|---|---|---|
| `no_grant` | Halt requires a current valid application grant. | [`halt`](/docs/apis/rt-control-http#halt), [`io_arm`](/docs/apis/rt-control-http#io-arm), [`io_disarm`](/docs/apis/rt-control-http#io-disarm), [`prepare_trajectory`](/docs/apis/rt-control-http#prepare-trajectory), [`start_program`](/docs/apis/rt-control-http#start-program) |
| `wrong_generation` | Halt carries a different application or native generation. | [`halt`](/docs/apis/rt-control-http#halt), [`io_arm`](/docs/apis/rt-control-http#io-arm), [`io_disarm`](/docs/apis/rt-control-http#io-disarm), [`prepare_trajectory`](/docs/apis/rt-control-http#prepare-trajectory), [`start_program`](/docs/apis/rt-control-http#start-program) |
| `inhibited` | Halt requires an armed, enabled machine with current readiness; Stop or a fault takes precedence. | [`halt`](/docs/apis/rt-control-http#halt), [`io_arm`](/docs/apis/rt-control-http#io-arm), [`io_disarm`](/docs/apis/rt-control-http#io-disarm), [`prepare_trajectory`](/docs/apis/rt-control-http#prepare-trajectory), [`start_program`](/docs/apis/rt-control-http#start-program) |
| `control_already_owned` | Another session holds authority, or a Stop is still draining. | [`acquire`](/docs/apis/rt-control-http#acquire) |
| `control_session_stale` | The session or generation is not the current one, the lease has expired, a Stop is in flight, or the lease cannot cover the measured round trip. | Every `POST /v1/control` operation that carries a fence |
| `session_principal_mismatch` | The session belongs to a different TLS principal/pair or local transport authority. | Every `POST /v1/control` operation that carries a fence |
| `daemon_restarted` | The session or snapshot belongs to a previous core incarnation. | Every `POST /v1/control` operation that carries a fence |
| `expired` | The lease deadline has passed. | [`renew`](/docs/apis/rt-control-http#renew), [`release`](/docs/apis/rt-control-http#release), [`stop`](/docs/apis/rt-control-http#stop) |
| `fence` | A well-formed session this adapter never issued, or authority revoked while a Start was in progress. | Every `POST /v1/control` operation that carries a fence |
| `authority_binding_mismatch` | `controller` is empty or longer than 63 bytes, or the binding's pair, revision or digest does not match the deployment. | [`acquire`](/docs/apis/rt-control-http#acquire) |
| `application_generation_exhausted` | The uint64 grant generation is exhausted; no further Acquire is possible without a restart. | [`acquire`](/docs/apis/rt-control-http#acquire) |
| `invalid_requested_lease` | Acquire requested lease is negative or exceeds the unverified absolute 10000 ms bound. | [`acquire`](/docs/apis/rt-control-http#acquire) |

### Handles

| Reason | Meaning | Returned by |
|---|---|---|
| `unknown_handle` | No such handle in this adapter incarnation. | [`start_trajectory`](/docs/apis/rt-control-http#start-trajectory), [`discard_trajectory`](/docs/apis/rt-control-http#discard-trajectory), [`start_program`](/docs/apis/rt-control-http#start-program) |
| `trajectory_identity_mismatch` | Raw trajectory Start identity differs from its immutable preparation. | [`start_trajectory`](/docs/apis/rt-control-http#start-trajectory) |
| `handle_active` | The handle has started, so it cannot be discarded. | [`discard_trajectory`](/docs/apis/rt-control-http#discard-trajectory) |
| `handle_started` | This handle has already started. | [`start_trajectory`](/docs/apis/rt-control-http#start-trajectory), [`start_program`](/docs/apis/rt-control-http#start-program) |
| `handle_consumed` | This handle completed or was replaced by a later execution. | [`start_trajectory`](/docs/apis/rt-control-http#start-trajectory), [`start_program`](/docs/apis/rt-control-http#start-program) |
| `handle_discarded` | This handle was explicitly discarded. | [`start_trajectory`](/docs/apis/rt-control-http#start-trajectory), [`start_program`](/docs/apis/rt-control-http#start-program) |
| `handle_superseded` | A committed replacement superseded this handle. | [`start_trajectory`](/docs/apis/rt-control-http#start-trajectory), [`start_program`](/docs/apis/rt-control-http#start-program) |
| `handle_retired` | Cancellation or uncertain ownership permanently retired this handle. | [`start_trajectory`](/docs/apis/rt-control-http#start-trajectory), [`start_program`](/docs/apis/rt-control-http#start-program) |

### Native admission

| Reason | Meaning | Returned by |
|---|---|---|
| `native_rejected` | Native command admission refused; inspect native_result. | Every `POST /v1/control` operation |
| `not_ready` | The controlled axes do not satisfy native movement readiness. | [`start_trajectory`](/docs/apis/rt-control-http#start-trajectory), [`start_program`](/docs/apis/rt-control-http#start-program). Also native command reason 2 inside `native_result`. |
| `mode_conflict` | Another active motion mode prevents this operation. | [`restore_anchor`](/docs/apis/rt-control-http#restore-anchor), [`begin_jog`](/docs/apis/rt-control-http#begin-jog), [`jog`](/docs/apis/rt-control-http#jog), [`start_trajectory`](/docs/apis/rt-control-http#start-trajectory), [`start_program`](/docs/apis/rt-control-http#start-program) |
| `outside_limits_outward` | A motion request increases an exterior limit excursion or crosses the opposite boundary; native command reason 8 and jog reason 15. | Every `POST /v1/control` operation |
| `pdo_mapping_mismatch` | Assigned PDO mapping differs from the registered layout; corrected bring-up is required. | Native command reason 7 in `native_result`, and fault bit 11 (`restart_required`) in `RecoveryStatus`. |

### Program admission and execution

| Reason | Meaning | Returned by |
|---|---|---|
| `busy` | An upload of the same kind is already in progress, the lifecycle lock is busy, or the core has no free plan slot. | [`prepare_trajectory`](/docs/apis/rt-control-http#prepare-trajectory), [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `program_identity_missing` | The `.rdt` header lacks a required identity field. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `program_identity_mismatch` | No program is prepared, or the supplied identity differs from it. | [`start_program`](/docs/apis/rt-control-http#start-program) |
| `program_already_executing` | A trajectory or program is executing. | [`reset_fault`](/docs/apis/rt-control-http#reset-fault), [`recovery_status`](/docs/apis/rt-control-http#recovery-status), [`prepare_program`](/docs/apis/rt-control-http#prepare-program), [`start_program`](/docs/apis/rt-control-http#start-program) |
| `manifest_revision_mismatch` | The program's `manifest_revision` differs from the adapter's pair revision. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `process_io_executor_not_qualified` | The program needs torch output, which is not qualified and always refused. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program), [`start_program`](/docs/apis/rt-control-http#start-program) |
| `dense_axis_map_requires_nine_ids` | The cell describes more rotary axes than the nine-column dense format carries. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `invalid_dense_axis_map` | The cell's rotary axes cannot be mapped onto the dense columns. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `unmapped_dense_axis` | The configured dense axis ID has no native axis mapping. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `native_limit_exceeded` | A dense sample exceeds a native position, velocity or declared sampled acceleration limit. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `native_segment_rate_exceeded` | An interpolated program segment exceeds a velocity limit. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `segment_boundary_discontinuous` | Rejected moving segment seam; boundary is the zero-based join index and gap_counts reports second minus first in source-axis counts. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `native_execution_failed` | Native execution ended without successful completion; motion completion is unverified. Inspect status and fault details, correct the cause, and explicitly prepare and start a new execution. | `execution.error` in `GET /v1/status` when a started program ends without completing. |

### Dense program format (.rdt)

| Reason | Meaning | Returned by |
|---|---|---|
| `dense_schema_mismatch` | Dense header schema does not name the supported dense trajectory format. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `header_truncated` | Dense header length or header bytes are incomplete. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `header_json_invalid` | Dense header cannot be decoded or encoded as JSON. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `sample_encoding_mismatch` | Dense record encoding or record byte count is unsupported. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `axis_count_mismatch` | Dense axis count differs from the nine-axis format. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `limits_invalid` | Dense velocity limits must contain nine positive finite values. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `segments_empty` | Dense program contains no motion segments. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `segment_index_out_of_order` | Dense segment indices do not follow payload order. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `kind_invalid` | Dense segment kind is not freespace, weld or dwell. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `segment_too_short` | Dense segment contains fewer than two samples. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `block_layout_invalid` | Dense block offsets, record lengths or segment metadata counts are inconsistent. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `blob_length_mismatch` | Dense payload length differs from the declared block extents. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `block_sha256_mismatch` | Dense segment bytes do not match their declared SHA-256 digest. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `reserved_flags_set` | Dense sample sets a reserved process flag bit. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `total_sample_count_mismatch` | Dense total sample count differs from its segment counts. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `sample_count_overflow` | Dense source sample count exceeds the format capacity. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `trajectory_digest_mismatch` | Dense content digest differs from the declared trajectory digest. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `time_grid_invalid` | Dense sample clock is not on its declared positive time grid. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `nonfinite_sample` | Dense time, position or velocity sample is not finite. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `qd_limit_exceeded` | Dense supplied velocity exceeds its declared format limit. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `torch_outside_weld` | Dense torch flag is set outside a weld segment. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `q_step_exceeded` | Dense position step exceeds the format velocity allowance. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `boundary_qd_nonzero` | Rejected dense segment endpoint velocity above the stationary boundary tolerance. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `boundary_q_discontinuity` | Rejected dense segment position gap or accumulated normalisation correction above the boundary tolerance. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |
| `duration_mismatch` | Dense segment duration differs from its final sample clock. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |

### Recovery and anchors

| Reason | Meaning | Returned by |
|---|---|---|
| `reset_requires_inhibited` | The machine is armed, jogging, commissioning or homing, or no fresh observation arrived within 1 s. | [`reset_fault`](/docs/apis/rt-control-http#reset-fault), [`recovery_status`](/docs/apis/rt-control-http#recovery-status) |
| `fault_persists` | At least one fault condition still prevents clearing. | [`reset_fault`](/docs/apis/rt-control-http#reset-fault) |
| `recovery_observation_unavailable` | No matching native recovery observation arrived within 1 s. | [`restore_anchor`](/docs/apis/rt-control-http#restore-anchor), [`reset_fault`](/docs/apis/rt-control-http#reset-fault), [`recovery_status`](/docs/apis/rt-control-http#recovery-status) |
| `invalid_axis_mask` | The requested axis mask is empty or names an axis outside the configured group. | [`restore_anchor`](/docs/apis/rt-control-http#restore-anchor) |
| `anchor_missing` | No persisted anchor exists for the axis. | [`restore_anchor`](/docs/apis/rt-control-http#restore-anchor) |
| `anchor_identity_mismatch` | The persisted anchor was recorded under a different configuration digest, drive identity or home epoch. | [`home`](/docs/apis/rt-control-http#home), [`restore_anchor`](/docs/apis/rt-control-http#restore-anchor) |
| `anchor_source_invalid` | The drive reports no valid absolute source for the axis. | [`home`](/docs/apis/rt-control-http#home), [`restore_anchor`](/docs/apis/rt-control-http#restore-anchor) |
| `anchor_disagrees` | The current absolute source disagrees with the persisted anchor beyond the profile tolerance. | [`restore_anchor`](/docs/apis/rt-control-http#restore-anchor) |
| `anchor_store_io` | Anchor storage could not be read or persisted; unverified stored evidence cannot authorize restoration. Filesystem details are logged locally and never returned in public feedback. Retry after checking the anchor directory and disk. On restore refusal, the anchor store is not modified. | [`home`](/docs/apis/rt-control-http#home), [`restore_anchor`](/docs/apis/rt-control-http#restore-anchor) |

### Cell I/O

| Reason | Meaning | Returned by |
|---|---|---|
| `io_not_configured` | named cell I/O is not configured. | [`io_arm`](/docs/apis/rt-control-http#io-arm), [`io_disarm`](/docs/apis/rt-control-http#io-disarm), [`prepare_trajectory`](/docs/apis/rt-control-http#prepare-trajectory), [`prepare_program`](/docs/apis/rt-control-http#prepare-program), [`start_program`](/docs/apis/rt-control-http#start-program) |
| `io_not_armed` | Explicit io_arm is required before an ON intent. | [`io_arm`](/docs/apis/rt-control-http#io-arm), [`io_disarm`](/docs/apis/rt-control-http#io-disarm), [`prepare_trajectory`](/docs/apis/rt-control-http#prepare-trajectory), [`start_program`](/docs/apis/rt-control-http#start-program) |
| `io_fast_input_unsatisfied` | A cyclic fast contact is invalid or not satisfied. | [`io_arm`](/docs/apis/rt-control-http#io-arm), [`io_disarm`](/docs/apis/rt-control-http#io-disarm), [`prepare_trajectory`](/docs/apis/rt-control-http#prepare-trajectory), [`start_program`](/docs/apis/rt-control-http#start-program) |
| `io_readback_disagreement` | Independent physical feedback disagrees with commanded output. | [`io_arm`](/docs/apis/rt-control-http#io-arm), [`io_disarm`](/docs/apis/rt-control-http#io-disarm), [`prepare_trajectory`](/docs/apis/rt-control-http#prepare-trajectory), [`start_program`](/docs/apis/rt-control-http#start-program) |
| `io_torch_unqualified` | torch-class markers remain refused pending hardware qualification. | [`io_arm`](/docs/apis/rt-control-http#io-arm), [`io_disarm`](/docs/apis/rt-control-http#io-disarm), [`prepare_trajectory`](/docs/apis/rt-control-http#prepare-trajectory), [`prepare_program`](/docs/apis/rt-control-http#prepare-program), [`start_program`](/docs/apis/rt-control-http#start-program) |
| `io_marker_late` | A process marker missed its one-cycle delivery bound. | [`io_arm`](/docs/apis/rt-control-http#io-arm), [`io_disarm`](/docs/apis/rt-control-http#io-disarm), [`prepare_trajectory`](/docs/apis/rt-control-http#prepare-trajectory), [`start_program`](/docs/apis/rt-control-http#start-program) |
| `io_exchange_lost` | Cell I/O has no current complete exchange. | [`io_arm`](/docs/apis/rt-control-http#io-arm), [`io_disarm`](/docs/apis/rt-control-http#io-disarm), [`prepare_trajectory`](/docs/apis/rt-control-http#prepare-trajectory), [`start_program`](/docs/apis/rt-control-http#start-program) |
| `io_marker_invalid` | A marker names an unknown output or has an invalid sample association. | [`prepare_program`](/docs/apis/rt-control-http#prepare-program) |

### Jog lane and jog clock

| Reason | Meaning | Returned by |
|---|---|---|
| `independent_jog_unavailable` | The native client offers no independent jog lane, or the remote listener is closing. | [`jog_clock`](/docs/apis/rt-control-http#jog-clock), [`jog_status`](/docs/apis/rt-control-http#jog-status), [`begin_jog`](/docs/apis/rt-control-http#begin-jog), [`update_jog`](/docs/apis/rt-control-http#update-jog), [`end_jog`](/docs/apis/rt-control-http#end-jog) |
| `jog_session_stale` | The jog session or its generation is not the current one. | [`update_jog`](/docs/apis/rt-control-http#update-jog), [`end_jog`](/docs/apis/rt-control-http#end-jog) |
| `jog_session_or_sequence_stale` | No open jog session for this generation, or the source sequence did not increase. | [`update_jog`](/docs/apis/rt-control-http#update-jog) |
| `jog_publisher_busy` | Another producer is publishing jog input at the same moment. | [`update_jog`](/docs/apis/rt-control-http#update-jog) |
| `jog_invalid_frame` | A binary jog frame could not be decoded. | [`update_jog`](/docs/apis/rt-control-http#update-jog) |
| `jog_stream_idle` | Rejected: no complete jog stream frame within the cell's jog input-age ceiling (250 ms on LAN). | [`update_jog`](/docs/apis/rt-control-http#update-jog) |
| `jog_clock_unqualified` | Remote clock qualification is disabled (the `--remote-jog-*` flags are 0) or calibration is incomplete. | [`update_jog`](/docs/apis/rt-control-http#update-jog) |
| `jog_clock_invalid_budget_or_exchange` | A malformed calibration or Begin message, or an invalid timing budget. | [`update_jog`](/docs/apis/rt-control-http#update-jog) |
| `jog_clock_incarnation_mismatch` | The clock incarnation is empty or differs from the negotiated one. | [`begin_jog`](/docs/apis/rt-control-http#begin-jog), [`update_jog`](/docs/apis/rt-control-http#update-jog) |
| `jog_clock_mapping_generation_mismatch` | The input was mapped with an out-of-date clock mapping. | [`update_jog`](/docs/apis/rt-control-http#update-jog) |
| `jog_clock_moved_backwards` | A source timestamp went backwards, or input predates the Begin sample. | [`update_jog`](/docs/apis/rt-control-http#update-jog) |
| `jog_clock_arithmetic_range` | Converting a jog timestamp would overflow. | [`update_jog`](/docs/apis/rt-control-http#update-jog) |
| `jog_clock_uncertainty_exceeded` | The calibrated offset interval is wider than `--remote-jog-max-uncertainty-ns`. | [`update_jog`](/docs/apis/rt-control-http#update-jog) |
| `jog_clock_calibration_expired` | The remote clock calibration is older than `--remote-jog-calibration-max-age-ns`. | [`update_jog`](/docs/apis/rt-control-http#update-jog) |
| `jog_clock_exchange_inconsistent` | The calibration timestamps are not causally consistent. | [`update_jog`](/docs/apis/rt-control-http#update-jog) |
| `jog_input_too_old` | The conservatively mapped input age exceeds the cell's input-age ceiling. | [`update_jog`](/docs/apis/rt-control-http#update-jog) |
| `jog_input_entirely_future` | The whole input interval lies in the host's future. | [`update_jog`](/docs/apis/rt-control-http#update-jog) |
| `jog_input_deadline_expired` | The input's deadline has already passed. | [`update_jog`](/docs/apis/rt-control-http#update-jog) |

### Events, telemetry and resources

| Reason | Meaning | Returned by |
|---|---|---|
| `invalid_event_cursor` | Event cursor must be a single unsigned decimal uint64. | [`subscribe_events`](/docs/apis/rt-control-http#subscribe-events) |
| `event_cursor_ahead` | Cursor exceeds this adapter incarnation's newest event; obtain current status/incarnation before resuming. | [`subscribe_events`](/docs/apis/rt-control-http#subscribe-events) |
| `event_cursor_lost` | Event history was lost; reconcile status before resuming from a new cursor. | [`subscribe_events`](/docs/apis/rt-control-http#subscribe-events). Client side: the C++ `EventCursorLost` exception. |
| `invalid_telemetry_cursor` | Telemetry after must be one unsigned decimal uint64 cursor. | [`telemetry`](/docs/apis/rt-control-http#telemetry) |
| `telemetry_cursor_ahead` | Telemetry cursor exceeds the current ring sequence; reconcile incarnation before restarting. | [`telemetry`](/docs/apis/rt-control-http#telemetry) |
| `telemetry_busy` | Ring header remained torn after the bounded 16 samples; retry the same cursor. Established streams continue with an empty batch and unchanged cursor. | [`telemetry`](/docs/apis/rt-control-http#telemetry) |
| `telemetry_unavailable` | A compatible live telemetry ring could not be observed. | [`telemetry`](/docs/apis/rt-control-http#telemetry) |
| `telemetry_label_invalid` | Telemetry label must contain 1..128 valid UTF-8 bytes. | [`mark_telemetry`](/docs/apis/rt-control-http#mark-telemetry) |
| `resource_unknown` | Digest is malformed or absent from the loaded compiled resource set; HTTP 404. | [`resource`](/docs/apis/rt-control-http#resource) |

### WebSocket transport (remote jog)

| Reason | Meaning | Returned by |
|---|---|---|
| `invalid websocket upgrade` | Missing or wrong upgrade headers, or a `Sec-WebSocket-Key` that is not 16 bytes. | WSS upgrade: HTTP 400, text/plain. |
| `hijacking unavailable` | The server could not take over the connection for the WebSocket. | WSS upgrade: internal; the upgrade is abandoned. |
| `fragmentation rejected` | A fragmented or continuation WebSocket frame was received. | WSS: connection closed with code 1009. |
| `invalid frame flags` | Reserved WebSocket bits are set, or a client frame is not masked. | WSS: reserved bits set or unmasked frame; closed with code 1002. |
| `noncanonical length` | A WebSocket payload length is not in its shortest encoding. | WSS: closed with code 1002. |
| `payload too large` | A WebSocket frame payload exceeds 4096 bytes. | WSS: frame over 4096 bytes; closed with code 1009. |
| `invalid opcode` | An unknown WebSocket opcode. | WSS: closed with code 1002. |
| `control payload too large` | A WebSocket control frame carries more than 125 bytes. | WSS: control frame over 125 bytes; closed with code 1002. |
| `invalid UTF-8` | A WebSocket text frame is not valid UTF-8. | WSS: text frame; closed with code 1007. |
| `invalid close payload` | A WebSocket close frame has a one-byte payload. | WSS: closed with code 1002. |
| `invalid close code` | A WebSocket close frame carries a reserved or invalid code. | WSS: closed with code 1002. |
| `invalid close reason` | A WebSocket close reason is not valid UTF-8. | WSS: closed with code 1007. |

### Remote TLS (startup and handshake)

| Reason | Meaning | Returned by |
|---|---|---|
| `remote pair-id required` | `--pair-id` is missing or not a valid token while the remote listener is enabled. | rt-control startup; exits with status 2. |
| `remote CA, certificate, key and CRL are required` | `--remote-listen` is set but a CA, certificate, key or CRL path is missing. | rt-control startup; exits with status 2. |
| `remote CA must contain one CA certificate` | The CA file is not exactly one PEM certificate. | rt-control startup; exits with status 2. |
| `remote CA must be a self-signed component CA` | The CA certificate is not a CA, or is not self-signed. | rt-control startup; exits with status 2. |
| `invalid remote CRL PEM` | The CRL file is not a PEM `X509 CRL`. | rt-control startup; exits with status 2. |
| `unsupported critical CRL extension` | The CRL has a critical extension that rt-control does not support. | rt-control startup; exits with status 2. |
| `remote CRL not current` | The current time is outside the CRL's validity window. | Startup (exit 2), and every later TLS handshake. |
| `remote client must be issued directly by component CA` | The client chain is not exactly the leaf plus the component CA. | TLS handshake: the client is refused before any HTTP request. |
| `remote client revoked` | The client certificate's serial number is on the CRL. | TLS handshake: the client is refused before any HTTP request. |
| `remote identity SAN must be an opaque token` | A `rosie-principal` or `rosie-pair` URI has a host, user, path, query or fragment. | TLS handshake: the client is refused before any HTTP request. |
| `invalid remote principal SAN` | The client certificate has more than one `rosie-principal` URI, or its token is invalid. | TLS handshake: the client is refused before any HTTP request. |
| `invalid remote pair SAN` | The client certificate has more than one `rosie-pair` URI, or its token is invalid. | TLS handshake: the client is refused before any HTTP request. |
| `remote principal/pair binding mismatch` | The certificate lacks a principal or pair, or its pair is not this cell's `--pair-id`. | TLS handshake: the client is refused before any HTTP request. |

### Startup and socket ownership

| Reason | Meaning | Returned by |
|---|---|---|
| `invalid_pair_configuration_binding` | At startup: `--pair-id` is empty, `--pair-revision` is 0, or `--configuration-sha256` does not match the core. | rt-control startup; exits. |
| `resource_artifact_invalid` | Startup refuses an incomplete, mismatched, malformed or over-bound compiled resource artefact. | rt-control startup; exits. |
| `socket owned by a live process` | Another live process holds the socket's lock. rt-control exits with status 3. | rt-control startup; exits with status 3. |
| `socket ownership cannot be verified` | The existing socket path is not a socket owned by this user. | rt-control startup; exits. |
| `socket lock ownership cannot be verified` | The `.lock` file beside the socket is not a private regular file owned by this user. | rt-control startup; exits. |
| `socket lock path changed` | The `.lock` file was replaced while rt-control was claiming it. | rt-control startup; exits. |
| `bound path is not a socket` | After binding, the socket path is not the expected socket. | rt-control startup; exits. |
| `process start time unavailable` | rt-control could not read its own start time to record socket ownership. | rt-control startup; exits. |
| `unsupported socket ownership transport` | An internal socket type other than stream or datagram was requested. | rt-control startup; exits. |

Four error texts carry detail after a fixed prefix: `unmapped_dense_axis: <axis>`, `native_limit_exceeded: segment=<index> sample=<index> axis=<id>`, `discard preparation <handle>: <cause>` and `jog_native_rejected_<number>` (a WebSocket jog refusal carrying a [native jog reason](https://advancedmetalresearch.com/docs/reference/error-codes#native-jog-reasons)). At startup, `remote CRL signature: <cause>` reports a CRL that the CA did not sign.

## Native command reasons

The numeric `native_result.Reason` in a refused command, from `reasons` in `rt-core/protocol/control.json`. `native_result.Result` is 0 accepted, 1 rejected or 2 prepared.

| Code | Name |
|---|---|
| 0 | `none` |
| 1 | `invalid_command` |
| 2 | `not_ready` |
| 3 | `mode_conflict` |
| 4 | `unknown_handle` |
| 5 | `capacity` |
| 6 | `invalid_trajectory` |
| 7 | `pdo_mapping_mismatch` |
| 8 | `outside_limits_outward` |
| 9 | `no_grant` |
| 10 | `wrong_generation` |
| 11 | `inhibited` |
| 12 | `io_not_configured` |
| 13 | `io_not_armed` |
| 14 | `io_fast_input_unsatisfied` |
| 15 | `io_readback_disagreement` |
| 16 | `io_torch_unqualified` |
| 17 | `io_marker_late` |
| 18 | `io_exchange_lost` |

rt-control translates some of these into labels: 8 becomes `outside_limits_outward`, the cell I/O reasons 9..18 become their labels for I/O-carrying calls, and 2 or 3 during a Start become `not_ready` or `mode_conflict`. Anything else arrives as `native_rejected`. Reason 5 (capacity) during a program upload arrives as `busy`, and reason 6 (invalid trajectory) retires every prepared handle.

## Native jog reasons

The numeric reasons of the jog lane, from `jog_reasons` in `control.json`. They appear in `JogObservation` (`StateReason`, `ControlReason`, `UpdateReason`), in `/v1/jog/ingress` counters and in WebSocket `jog_native_rejected_<n>` refusals. Reason 14 (`limited`) is an accepted, governed state, not a failure.

| Code | Name |
|---|---|
| 0 | `none` |
| 1 | `closed` |
| 2 | `mode_conflict` |
| 3 | `not_ready` |
| 4 | `wrong_identity` |
| 5 | `invalid_generation` |
| 6 | `stale_sequence` |
| 7 | `invalid_vector` |
| 8 | `invalid_timing` |
| 9 | `expired` |
| 10 | `authority_lost` |
| 11 | `clock_reset` |
| 12 | `generation_exhausted` |
| 13 | `ramping` |
| 14 | `limited` |
| 15 | `outside_limits_outward` |

## Native grant reasons

The numeric `GrantReason` in `GrantObservation`, from `grant_reasons` in `control.json`.

| Code | Name |
|---|---|
| 0 | `none` |
| 1 | `invalid` |
| 2 | `connection_mismatch` |
| 3 | `native_generation_mismatch` |
| 4 | `disconnected` |
| 5 | `busy` |
| 6 | `not_inhibited` |
| 7 | `stale_generation` |
| 8 | `identity_mismatch` |
| 9 | `expired` |
| 10 | `clock_regression` |
| 11 | `inactive` |
| 12 | `axis_mask_mismatch` |

## Execution fault bits

`core.execution_fault_reasons` in Status is a bit mask of latched execution faults. `RecoveryStatus.faults[]` names each latched bit with its affected axes and recovery class. This table is generated from `rt-core/include/fault_recovery.hpp`, whose own comments call the policy unverified.

| Bit | Name | Invalidates Home | Needs drive reset | Needs reverification | Recovery class |
|---|---|---|---|---|---|
| 0 | `start_discontinuity` | No | No | No | `reset_clears` |
| 1 | `position_rate` | Yes | No | No | `rehome_required` |
| 2 | `cycle_deadline` | No | No | No | `reset_clears` |
| 3 | `cycle_sleep` | No | No | No | `reset_clears` |
| 4 | `target_lead` | Yes | No | No | `rehome_required` |
| 5 | `following_error` | No | No | No | `reset_after_condition_clears` |
| 6 | `coordinate_reference` | Yes | No | No | `rehome_required` |
| 7 | `drive_readiness` | No | Yes | Yes | `reset_after_condition_clears` |
| 8 | `bus_transport` | No | No | Yes | `reset_after_condition_clears` |
| 9 | `completion_timeout` | No | No | No | `reset_clears` |
| 10 | `brake_hold` | No | No | Yes | `restart_required` |
| 11 | `pdo_mapping_mismatch` | Yes | No | Yes | `restart_required` |
| 12 | `collision_watchdog` | No | No | No | `reset_after_condition_clears` |
| 13 | `cell_io` | No | No | No | `restart_required` |

Loss of trusted feedback can also require Home even when the table says No. Unknown bits persist.

| Recovery class | What to do |
|---|---|
| `reset_clears` | `reset_fault` clears it. |
| `reset_after_condition_clears` | Remove the cause first (fresh feedback below the bound, a healthy bus, drives fault-free), then `reset_fault`. |
| `rehome_required` | `reset_fault`, then Home (or a qualified `restore_anchor`) on the axes in `rehome_axis_mask` before any motion. |
| `restart_required` | Reset cannot clear it. Investigate, then restart the core. |

`reset_fault` outcomes per bit are `cleared`, `persists` or `rehome_required`. Any persistent selected condition refuses the whole reset with `fault_persists`.

## Axis readiness

Each entry of `axes[]` in Status has a `readiness` string: the first failing gate for that axis, in this order. It is an observation, not authority: the group gates (lease, Arm, bus, faults, configuration) still apply at every Start.

| Order | Value | What to do |
|---|---|---|
| 1 | `faulted` | A drive alarm or latched safety fault. Diagnose it and follow its recovery class. |
| 2 | `mode_mismatch` | The drive is not in CSP mode (8). Wait for an expected commissioning transition, or restore the mode. |
| 3 | `home_required` | Home, or a qualified `restore_anchor`, before Start. |
| 4 | `coordinate_invalid` | Coordinates are not trustworthy. Restore feedback, configuration or Home evidence. |
| 5 | `not_enabled` | Enable the axis under a live grant. |
| 6 | `not_operation_enabled` | Wait for the CiA402 transition to Operation Enabled. |
| 7 | `brake_wait` | Wait for the brake release delay. |
| 8 | `ready` | This axis passes. Check the whole selected group and the grant before Start. |

The code also defines `warning_tolerated`: one tolerated drive warning on an axis without an encoder battery. It grants nothing, and Home and Enable keep their normal gates.

## Handle states

`HandleRecord.state`, from `handle_states` in the schema. Only `prepared` can start, and terminal states never regain permission.

| State | Meaning |
|---|---|
| `prepared` | Native preparation acknowledged. Start may be attempted under current authority. |
| `started` | Native Start accepted. Observe completion. |
| `consumed` | Completed, or a later execution replaced it. |
| `discarded` | Discarded. |
| `superseded` | A newer preparation replaced it. |
| `retired` | Stop, grant or connection loss, or an uncertain outcome. Never startable again. |

## Other components

Components that call rt-control add their own refusal codes. They are documented with each component:

| Component | Codes | Page |
|---|---|---|
| Dense trajectory daemon | `native_grant_active`, `native_acquisition_required`, `native_home_unavailable`, `native_torch_unsupported`, `pause_unsupported`, `cleanup_uncertain`, `home_required` | [Dense trajectory daemon](https://advancedmetalresearch.com/docs/apis/dense-trajectory-daemon) |
| Cartesian motion server | `rt_core_position_input_unresolved`, `rt_core_run_not_admitted`, `rt_core_home_abandoned` | [Cartesian motion server](https://advancedmetalresearch.com/docs/apis/cartesian-motion-server) |
| Offline programming server | `target_changed`, `cell_configuration_mismatch`, `backend_retired`, `motion_plan_seam_refused`, `motion_plan_unjoined`, `motion_plan_no_trajectory` | [Offline programming HTTP API](https://advancedmetalresearch.com/docs/apis/olp-http) |
| Weld planner admission | `motion_join_failed`, `seam_not_planned`, `motion_not_verified`, `motion_result_invalid`, `candidate_only_requires_m4` | [Weld planner HTTP API](https://advancedmetalresearch.com/docs/apis/weld-planner-http) |

## Sources

Written from these files in the RosieOS repository (https://github.com/advanced-metal-research/RosieOS):

- `rt-core/protocol/application-v1.schema.json:421 (reasons)`
- `rt-core/protocol/application-v1.schema.json:413 (handle_states)`
- `rt-core/protocol/control.json (reasons, jog_reasons, grant_reasons, results)`
- `rt-core/include/fault_recovery.hpp:26-64`
- `rt-core/include/motion_readiness.hpp:14-21`
- `rt-core/adapters/rosie/control/http.go:247-283`
- `rt-core/adapters/rosie/control/handles.go:5-19`
- `rt-core/adapters/rosie/control/cell_io_linux.go:77-88`
- `rt-core/adapters/rosie/control/websocket.go:80-148`
- `rt-core/adapters/rosie/control/remote_tls.go:22-160`
- `rt-core/adapters/rosie/control/socket_owner.go:19-149`
- `rt-core/cmd/rt-control/main.go:199-213`
- `rt-core/engine/status_publisher.hpp:1065`
- `motion-server/joint-trajectory/v1/src/rt_control_executor.hpp`
- `motion-server/v1/src/rt_core_cartesian_runtime.hpp`
- `offline-programming/v1/weld_plan.go:502-530`
- `offline-programming/v1/internal/targets/picker.go`
- `weld_planner/v1/python/weldplan/native_admission.py:204-250`
