Run states and errors
A run moves through seven states, and a failed one carries a code, a detail and the stage it failed at.
Run states
Section titled “Run states”run.status is the state machine contracts/state-machines/run-v4.json declares.
| State | Terminal | Meaning |
|---|---|---|
queued |
no | accepted and waiting for a worker |
running |
no | a worker holds it |
awaiting_confirmation |
no | the run is over the projection threshold and needs a --confirm before it starts |
awaiting_sample_approval |
no | an existing legacy preview hold or a repair hold; new full builds do not create sample/full pairs |
succeeded |
yes | it finished |
failed |
yes | it stopped, and the record says why |
cancelled |
yes | somebody cancelled it, or a gate expired |
The transitions, and who may make them:
| Transition | From | To | Actor |
|---|---|---|---|
create |
none | queued |
workspace editor |
require_confirmation |
none | awaiting_confirmation |
workspace editor |
require_sample_approval |
none | awaiting_sample_approval |
workspace editor |
confirm |
awaiting_confirmation |
queued |
workspace editor |
approve_full |
awaiting_sample_approval |
queued |
workspace editor |
expire_confirmation |
awaiting_confirmation |
cancelled |
Studio |
expire_sample_approval |
awaiting_sample_approval |
cancelled |
Studio |
abort_sampled_full |
awaiting_sample_approval |
cancelled |
Studio |
start |
queued |
running |
Studio |
succeed |
running |
succeeded |
Studio |
fail |
queued, running |
failed |
Studio |
terminalize_lost_execution |
running |
failed |
Studio |
cancel |
queued, awaiting_confirmation, awaiting_sample_approval, running |
cancelled |
workspace editor |
A failed run carries failure_code, failure_detail and failed_stage, or it is not a valid record.
mr-data status RUN_ID exits 2 on a failed run. mr-data run exits 2 when the run comes back awaiting_confirmation.
Outcome
Section titled “Outcome”A succeeded run carries outcome:
| Value | Meaning |
|---|---|
version |
the run wrote a new table version. An absent member means the same |
unchanged |
every source’s bytes matched the predecessor’s, so the worker stopped after acquisition. No transform, no write, no upload, no receipt, no table version. The table’s last_refresh advances and the live pointer stays put |
unchanged is legal only on mode refresh. An initial, full, sample or backfill has no predecessor to compare against.
Run modes
Section titled “Run modes”One run command takes six modes.
| Mode | Flag | What it does |
|---|---|---|
sample |
--sample |
an explicit bounded experiment. State at least one ceiling; row limits do not limit acquisition time |
full |
--full |
one progressive acquisition of the whole build. Any required confirmation happens before acquisition; its inspection checkpoint continues automatically |
refresh |
--refresh |
forward from where the last successful run reached |
backfill |
--backfill |
one exact window, stated with --window START END |
compact |
--mode compact |
rewrites adjacent parts of an existing version. Reads no source |
replay |
--mode replay |
restores the retained raw bytes of --sources-from RUN_ID. Never advances live state and never acquires from a publisher |
Worker stages
Section titled “Worker stages”failed_stage is one of five, in order.
| Stage | What runs |
|---|---|
acquire |
the worker fetches or redeems every declared source |
parse |
the Reader decodes the bytes into a relation |
transform |
the declared SQL steps run over the source relations |
check |
the worker evaluates the declared checks |
persist |
the worker uploads and stores the table version and its artifacts |
The acquire stage reports three phases: fetching, fetched, refused.
Run shape
Section titled “Run shape”Studio stamps run.shape at admission and never re-derives it.
| Shape | What it is |
|---|---|
warm |
the warm session-worker pool |
ready |
the general ready worker pool, capacity-based |
ingestion |
the bounded-direct ingestion path, legal only for a source-history.v2 bounded direct refresh |
batch |
a batch job |
A source with a Reader pin, a generic API configuration, or a document projection needs a per-child memory cgroup and a capture-store mount. Admission stamps it batch. Both pool shapes fall back durably to batch when nothing claims them.
Run events
Section titled “Run events”mr-data watch RUN_ID reads an append-only log. event_type has eight values, each with a writer.
| Event | Written by |
|---|---|
run_progress_acquire |
the worker, once per acquire progress tick |
run_progress_parse |
the worker |
run_progress_transform |
the worker |
run_progress_check |
the worker |
run_progress_persist |
the worker |
run_succeeded |
the worker’s terminal callback |
run_failed |
the worker’s terminal callback, or Studio’s lease watchdog |
run_narrative_appended |
POST /v4/runs/{run_id}/narrative, one per accepted cell |
No run_created, run_started or run_cancelled event exists. Nothing writes them. Each record carries schema_version, event_id, workspace_id, run_id, cursor (the SSE id), sequence, event_type, occurred_at, actor_principal_id and payload_digest. Every one of those fields is mandatory. attempt_id and unsealed are optional, and the record accepts nothing else. A progress message is at most 1024 characters. A progress identifier is at most 63.
The refusal envelope
Section titled “The refusal envelope”Studio v4 returns an error as application/problem+json with an x-correlation-id header.
{ "schema_version": "4.0.0", "code": "RECIPE_DIGEST_MISMATCH", "message": "The registered recipe does not have that digest.", "request_id": "a2f4…", "details": [ { "pointer": "/document/sources/0/limits", "reason": "max_source_bytes is required" } ]}| Field | Required | Shape |
|---|---|---|
schema_version |
yes | 4.0.0 |
code |
yes | ^[A-Z][A-Z0-9_]*$, 3 to 64 characters. A pattern, not a frozen enum |
message |
yes | 1 to 2000 characters |
request_id |
yes | 1 to 200 characters |
details |
no | at most 20 entries, each one of three closed shapes |
A details entry is one of three shapes:
{pointer, reason}is the validation shape.pointeris at most 512 characters,reasonat most 2000.{run_id, projected_bytes, projected_runtime_s, projected_cost}is the body of409 CONFIRM_REQUIRED.{recorded_cost, requested_cost, ceiling_cost}is the body of409 DAILY_SPEND_CEILING_EXCEEDED.
A run that answers 409 CONFIRM_REQUIRED already exists, persisted awaiting_confirmation, so the confirmation acts on it rather than repeating the request. projected_cost is a decimal string. Money is never a JSON float here. The plan is flat, so that figure is the platform’s own infrastructure estimate and is never billed to you.
The CLI’s own envelope
Section titled “The CLI’s own envelope”With --json, an error is one object on stderr, and the exit code is 2.
{ "schema_version": "mr-data-error.v1", "code": "THIN_STUDIO_RECIPE_DIGEST_MISMATCH", "error": "The registered recipe does not have that digest.", "headline": "The registered recipe does not have that digest.", "remediation": ["…"], "retry_after_seconds": 30}The CLI preserves Studio’s code and adds a prefix. A Studio RECIPE_DIGEST_MISMATCH reaches a script as THIN_STUDIO_RECIPE_DIGEST_MISMATCH, with Studio’s own message. A query refusal takes its family as the prefix and drops the repeated word. Studio’s QUERY_TIMEOUT reaches a script as THIN_QUERY_TIMEOUT, never THIN_QUERY_QUERY_TIMEOUT. Two statuses fold instead of passing through. 401 and 403 both become THIN_AUTHORIZATION_DENIED, with Studio’s code named in the sentence, and 404 becomes THIN_NOT_FOUND.
Client codes
Section titled “Client codes”mr-data raises these before or around a request. They carry no HTTP status.
| Code | Raised when | What the author does |
|---|---|---|
THIN_UNKNOWN_COMMAND |
the argument list names no command this binary runs | mr-data --help lists them |
THIN_ARGUMENT_INVALID |
a flag’s value is not the shape the flag takes | fix the argument |
THIN_REQUEST_INVALID |
the request this command would send is not well formed | fix the input document or flags |
THIN_CONFIG_INVALID |
a configured origin is not usable | check MOSTLYRIGHT_* environment variables |
THIN_AUTHENTICATION_FAILED |
Studio rejected the stored device credential | mr-data login |
THIN_AUTHORIZATION_DENIED |
the device key does not carry the authority this call needs | check the workspace role. Studio’s own code is in the sentence |
THIN_SUBSCRIPTION_REQUIRED |
cloud answered 402 | the workspace has no hosted execution access |
THIN_RATE_LIMITED |
cloud answered 429 | honour retry_after_seconds |
THIN_TOKEN_EXCHANGE_FAILED |
the CLI could not reach the cloud token exchange, or it returned an expired token | retry. If it persists, cloud’s Studio config is wrong |
THIN_STUDIO_UNAVAILABLE |
cloud answered 503 across every attempt | retry later |
THIN_STUDIO_UNREACHABLE |
Studio did not answer | retry later |
THIN_STUDIO_REFUSED |
Studio refused the request with no code in the body | read http_status on the refusal |
THIN_STUDIO_<CODE> |
Studio refused the request with a v4 code | see Studio refusal codes |
THIN_NOT_FOUND |
Studio has no such resource | check the identifier. A resource in another workspace reads identically |
THIN_RESPONSE_INVALID |
the CLI could not parse a reply | client and backend sit on different contract versions |
THIN_RESPONSE_TOO_LARGE |
a reply exceeded the byte ceiling for its route (1 MiB for JSON) | narrow the request |
THIN_RECIPE_DOCUMENT_UNREADABLE |
the CLI could not read the recipe file | check the path |
THIN_RECIPE_DOCUMENT_INVALID |
the recipe file is not strict JSON | a recipe carries integers, strings, booleans, null, objects and lists, and never a fractional number |
THIN_CONFIRMATION_MISMATCH |
--confirm-name did not match the held name |
type the name on the page |
THIN_DATASET_VERSION_CONFLICT |
the dataset moved again during a retried rename | mr-data dataset show, then rename again |
THIN_NO_SEALED_RESULT |
the run has written nothing to read yet | mr-data watch RUN_ID |
THIN_NO_CHECK_RESULTS |
the run has not finished, so checks have not reported | mr-data watch RUN_ID |
THIN_NO_PREVIEW_SEALED |
the run composed a multi-part version and wrote no preview | mr-data query RUN_ID |
THIN_NO_MATCHING_ARTIFACT |
the run wrote no artifact of the requested --kind |
ask for a kind it wrote |
THIN_NOTHING_LIVE |
the table carries a promotion but no succeeded run resolves to a version | build it once successfully |
THIN_NO_RELEASED_VERSION |
the run released no version | check mr-data status |
THIN_NO_FINGERPRINT |
the run’s evidence carries no fingerprint | nothing can compare it with another run |
THIN_DESTINATION_EXISTS |
the output path holds a different file | a download never overwrites a local file |
THIN_ARTIFACT_TOO_LARGE |
the artifact declares more than 16 GiB | not downloadable through the client |
THIN_DOWNLOAD_DIGEST_MISMATCH |
the bytes do not hash to the digest Studio declared | retry. Report it if it repeats |
THIN_DOWNLOAD_TRUNCATED |
fewer bytes arrived than Studio declared | retry |
THIN_DOWNLOAD_OVERRUN |
more bytes arrived than Studio declared | retry |
THIN_DOWNLOAD_REFUSED |
the signed download answered non-200 | the session may have expired. Run download again |
THIN_VERSION_PART_UNREACHABLE |
the version names parts for which Studio created no read URL | a table missing parts is a table missing rows. The CLI reports nothing as downloaded |
THIN_QUERY_STATEMENT_TOO_LARGE |
the statement is over 64 KiB | shorten it. The CLI sent nothing |
THIN_QUERY_TIMEOUT |
the wait ended before the answer | the question keeps running. Run the same command again |
THIN_QUERY_BINDER_ERROR |
the statement does not bind against the table | check the column names against mr-data peek |
THIN_STREAM_REFUSED |
Studio refused the event-stream request | retry watch |
THIN_STREAM_UNAVAILABLE |
the CLI could not re-establish the event stream | the run continues. Resume watch |
THIN_STREAM_FRAME_INVALID |
a stream frame carried a body that is not JSON | contract mismatch |
THIN_SECRET_MATERIAL_INVALID |
a --part holds more than the vault stores as one value |
shrink the part |
THIN_RESEARCH_SESSION_ENDED |
no worker took the session this command opened | retry |
THIN_RESEARCH_SOURCE_FORBIDDEN |
the source is not one this session may probe | open the session against the right dataset |
THIN_NOTEBOOK_NOT_RENDERED |
Studio renders a notebook when the run finishes | mr-data watch until then |
THIN_COMMAND_UNAVAILABLE |
this build registers no such command | mr-data --help |
THIN_COMMAND_HAS_NO_HOSTED_LANE |
the command does not run on the backend | it does not run here |
THIN_CLOUD_REFUSED |
cloud refused and stated nothing usable | the sentence quotes what cloud said |
THIN_CLOUD_STEP_UP_REQUIRED |
publishing needs a verification only a signed-in browser finishes | open the dashboard and share from that page |
THIN_CLOUD_PUBLIC_SHARING_DISABLED |
the organization does not allow public datasets | an owner changes it |
THIN_CLOUD_PUBLISHER_PROFILE_REQUIRED |
the organization has no publisher name | set it in team settings |
The full client vocabulary is larger. The propose bundle commands, the cancellation journal and the narrative editor each add codes under THIN_PROPOSE_*, THIN_CANCELLATION_* and THIN_NARRATIVE_*. Each states its own sentence and its own fix.
Studio refusal codes
Section titled “Studio refusal codes”Studio v4 raises these and answers them as problem+json. The message column is Studio’s own wording.
Recipe and registration
Section titled “Recipe and registration”| Code | HTTP | Message | What the author does |
|---|---|---|---|
RECIPE_DIGEST_MISMATCH |
409 | The registered recipe does not have that digest. | pass the digest registration printed |
RECIPE_DOCUMENT_NOT_CANONICAL |
422 | The recipe document cannot be canonicalized. | remove fractional numbers and duplicate keys |
RECIPE_DOCUMENT_INCOHERENT |
422 | The recipe document is internally inconsistent. | read details[].pointer |
RECIPE_UNAVAILABLE |
409 | This table has no registered recipe to build from. | register one |
DATASET_ID_REQUIRED |
422 | Create and categorize the dataset first, then put its id in document.dataset.id. |
mr-data dataset create |
DATASET_CATEGORY_REQUIRED |
422 | Choose a primary category with dataset set --category before registering a recipe. |
mr-data dataset categories |
DATASET_MISMATCH |
409 | dataset.id names no V4 dataset of this workspace. |
check the id |
DATASET_NAME_CONFLICT |
409 | none | choose another name |
DATASET_ARCHIVED |
409 | This recipe’s dataset is archived and read-only. | unarchive it |
CONTRACT_VALIDATION_FAILED |
422 | none | the request does not match the v4 contract |
SECRET_UNKNOWN |
409 | This recipe names a secret this workspace has not enrolled. | mr-data keys set NAME |
SECRET_UNAVAILABLE |
409 | The secret this source names is no longer enrolled in this workspace. | re-enrol it |
CONNECTION_DATASET_REQUIRED |
409 | Create a dataset and grant it access to this connection, then specify dataset.id. |
an owner grants it in Settings |
CONNECTION_AUTHORITY_MISMATCH |
422 | Recipe connector authority differs from its saved connection. | re-read the connection and re-register |
Starting a run
Section titled “Starting a run”| Code | HTTP | Message | What the author does |
|---|---|---|---|
CLAMPS_REQUIRED |
422 | A sample run must state at least one clamp. | pass --max-rows or --max-source-bytes |
CONFIRM_REQUIRED |
409 | This run is over the projection threshold and needs a confirmation before it starts. | re-run with --confirm. The projection is in details |
DAILY_SPEND_CEILING_EXCEEDED |
409 | none | the amounts are in details. Wait or raise the ceiling |
RUN_WINDOW_REQUIRED |
422 | A backfill run must state an exact window. | pass --window START END |
RUN_MODE_UNKNOWN |
422 | That is not a v4 run mode. | one of the six modes |
RUN_ALREADY_EXISTS |
409 | The identical run already ended. Register a revised recipe to run again. | revise and re-register |
TABLE_RUN_IN_FLIGHT |
409 | This table already has a mutating run. | wait, or cancel the one in flight |
TABLE_BUSY |
409 | A table with a run still in flight cannot start another. | wait |
TABLE_ARCHIVED |
409 | This run’s table is archived and no longer builds. | unarchive it |
BUILD_COMPLETE |
409 | The latest build already read every source whole. There is nothing to run. | nothing to do |
REPLAY_SOURCE_REQUIRED |
422 | A replay must name sources_from_run. |
pass --sources-from RUN_ID |
REPLAY_SOURCE_UNAVAILABLE |
409 | The named replay source is not a succeeded run of this table. | name a succeeded run of the same table |
REPLAY_SOURCE_EXPIRED |
409 | The named run no longer retains its raw snapshot and receipt. | replay is no longer possible for it |
REPLAY_WORKER_UNAVAILABLE |
409 | Replay is unavailable until a compatible worker is deployed. | wait for the deployment |
STATE_TRANSITION_INVALID |
409 | This full run is not awaiting sample approval. | read the run’s current state |
STEP_UP_BINDING_MISMATCH |
403 | Approval requires an interactive step-up bound to this full run version. | approve it in the dashboard. A run held behind a PREVIEW does not reach this code: any editor of the workspace releases that one. |
ETAG_MISMATCH |
412 | The run has moved since it was read. | re-read and retry |
IDEMPOTENCY_KEY_INVALID |
422 | Idempotency-Key must be 16 to 128 URL-safe characters. |
fix the header |
SCHEDULE_CADENCE_TOO_FREQUENT |
422 | That schedule refreshes the table more often than the platform allows. | slow the cadence |
SCHEDULE_CRON_INVALID |
422 | That cadence is not a satisfiable five-field cron expression. | fix the expression |
MANUAL_REFRESH_RATE_LIMITED |
429 | This workspace has requested 1,200 table refreshes in the current hour. | wait for the hour to turn |
Reading a table
Section titled “Reading a table”| Code | HTTP | Message | What the author does |
|---|---|---|---|
NOTHING_TO_PROMOTE |
409 | This table has no succeeded V4 run to promote. | build it once |
TABLE_NOT_PROMOTED |
409 | This table is not promoted. | the first succeeded run promotes it |
TABLE_LIVE |
409 | A live table cannot be archived. | demote it first |
TABLE_VERSION_UNAVAILABLE |
409 | none | the version is not readable |
TABLE_VERSION_ARTIFACT_UNAVAILABLE |
409 | This V4 table version has no stored artifact of that kind available. | ask for a kind it holds |
TABLE_PREVIEW_UNAVAILABLE |
none | none | the run wrote no preview |
QUERY_TOO_MANY_PARTS |
none | none | narrow the read with --field plus --from/--to, or --partition |
TABLE_COMPACTION_INELIGIBLE |
409 | This table has no bounded adjacent part group to compact. | nothing to compact |
TABLE_COMPACTION_RECIPE_CHANGED |
409 | Compaction must use the recipe that produced its predecessor version. | pass the predecessor’s recipe |
CURSOR_INVALID |
422 | The page cursor is not a position in this listing. | start the listing again |
Streams
Section titled “Streams”| Code | HTTP | Message |
|---|---|---|
STREAM_DOCUMENT_NOT_FOUND |
404 | No registered connector document in this workspace carries that digest. |
STREAM_VENUE_UNAVAILABLE |
503 | This deployment has not configured a continuous stream worker pool. |
STREAM_SUBSCRIPTION_MEMBERS_INVALID |
409 | This stream already feeds as many promoted tables as one subscription may. |
STREAM_RECORDING_MEMBERS_INVALID |
422 | A recordings listing scopes by member ids. |
STREAM_RECORDING_REQUEST_INVALID |
422 | A recordings listing is scoped by one connector document digest. |
RECORDING_MEMBERSHIP_CHANGED |
409 | One source exceeds the page budget. |
RUN_RECORDING_WATERMARK_MISMATCH |
409 | A stream source recorded a position other than the one it was dispatched. |
Worker callback codes
Section titled “Worker callback codes”An author never sends these. They appear on a failed run’s record when Studio refused a worker’s callback. ATTEMPT_STALE, ATTEMPT_FENCE_STALE, ATTEMPT_SCOPE_MISMATCH, ARTIFACT_SESSION_EXPIRED, ARTIFACT_KIND_UNKNOWN, ARTIFACT_KIND_ALREADY_RESERVED, UPLOAD_SESSION_BINDING_MISMATCH, SESSION_NOT_FOUND, SESSION_EXPIRED, CREDENTIAL_HANDLE_UNKNOWN, CREDENTIAL_HANDLE_CONSUMED, CREDENTIAL_AUTHORITY_STALE, and the FETCH_* family.
Every other v4 code reaches the CLI verbatim as THIN_STUDIO_<CODE> with Studio’s own message. Studio bounds that message at 2000 characters.
Worker failure codes
Section titled “Worker failure codes”These land on run.failure_code when a run fails. A run reports no code outside this list.
Acquisition
Section titled “Acquisition”| Code | Meaning | What the author does |
|---|---|---|
ACQUISITION_FAILED |
the worker could not fetch a source | read failure_detail. Check the address and the publisher |
ACQUISITION_FORMAT_UNMAPPED |
the response media type maps to no data format | pin a Reader whose accepted list carries it |
ACQUISITION_CHILD_INVALID |
the confined acquisition child did not behave | infrastructure. Report it |
SOURCE_HTTP_5XX |
the publisher answered a server error | retry later |
SOURCE_RATE_LIMITED |
the publisher rate-limited the fetch | raise min_interval_seconds, lower concurrency |
SOURCE_PROXY_BUSY |
the egress proxy had no room | retry |
FETCH_AUTHORITY_UNAVAILABLE |
the worker could not resolve the credential authority | check that the secret or connection remains enrolled |
RUN_CREDENTIAL_SCOPE_INVALID |
the credential’s scope does not cover this source | re-check credential on the source |
COLLECTION_DISCOVERY_FAILED |
the publisher refused a first run’s listing request | read the coverage block’s discovery_failure |
COLLECTION_MERGE_INVALID |
the collection’s pages did not merge | schemas differ between pages |
PREDECESSOR_UNAVAILABLE |
the worker could not read the predecessor version | the refresh has nothing to continue from |
PREDECESSOR_HOST_REFUSED |
the predecessor’s host refused the read | infrastructure |
BOUNDED_DIRECT_ROUTE_REFUSED |
the bounded-direct path refused this run | it falls back to batch |
Clamps and modes
Section titled “Clamps and modes”| Code | Meaning | What the author does |
|---|---|---|
CLAMP_EXCEEDED |
the run crossed a declared clamp | raise --max-rows / --max-source-bytes, or narrow the window |
CLAMP_UNSUPPORTED_FORMAT |
the clamp does not apply to this source. A document projection cannot run under a sample row clamp | run the projection as a full source |
RUN_CLAMPS_REQUIRED |
the mode needs a clamp and the run stated none | pass one |
RUN_CLAMPS_INVALID |
the clamps are not a legal set | --max-rows, --max-source-bytes, --window |
RUN_MODE_INVALID |
the mode does not fit this run | check the mode against the table’s state |
RUN_WINDOW_REQUIRED |
a backfill with no window | pass --window START END |
RUN_RECIPE_INVALID |
the job document’s recipe is not executable | read failure_detail. It names the source and the reason |
JOB_INVALID |
the async job block is not executable | check generic_api.job |
Transform
Section titled “Transform”| Code | Meaning | What the author does |
|---|---|---|
TRANSFORM_STATEMENT_NOT_SELECT |
a step is not a single read-only SELECT |
rewrite the step |
TRANSFORM_STATEMENT_NOT_SINGLE |
a step carries more than one statement | split it into steps |
TRANSFORM_STEP_DUPLICATE |
two steps share an id | rename one |
TRANSFORM_STEP_SHADOWS_SOURCE |
a step id collides with a source name | rename the step |
TRANSFORM_COLUMN_TYPE_MISMATCH |
the final SELECT returns a type the column declares otherwise |
cast(...) the column |
TRANSFORM_PLAN_INVALID |
the plan is not a runnable graph | check step order and references |
TRANSFORM_ENGINE_UNCONFINED |
the worker could not confine the engine | infrastructure |
COLUMN_PRESENTATION_INCOMPATIBLE |
a chart does not describe that column type | see Recipe document |
Checks
Section titled “Checks”| Code | Meaning | What the author does |
|---|---|---|
CHECK_FAILED |
a declared check with enforcement: required failed |
mr-data checks RUN_ID. Fix the recipe or accept the data |
DECLARED_CHECK_INVALID |
a check is not a legal declaration | see Checks |
DECLARED_CHECK_COLUMN_UNKNOWN |
a check names a column the table does not have | fix the name |
DECLARED_CHECK_DUPLICATE |
two checks share an id | rename one |
DECLARED_CHECK_UNREADABLE |
the worker could not read a check | fix the JSON |
DECLARED_CHECKS_INVALID |
the checks block as a whole is not legal | at most 128 checks |
Windows and snapshots
Section titled “Windows and snapshots”| Code | Meaning |
|---|---|
WINDOW_UNRENDERABLE |
the address carries raw braces, or an undeclared placeholder. Window templates are path-only |
WINDOW_FORMAT_UNSUPPORTED |
the source arrived in a format no window merges into |
WINDOW_MERGE_INVALID |
the slice’s columns are not the columns the previous run wrote |
WINDOW_PARTITION_UNREADABLE |
a row states no value in merge.partition.column that reads as a partition under the declared key |
WINDOW_ROWS_OUT_OF_RANGE |
the source returned rows outside the requested window |
WINDOW_SPAN_TOO_MANY_PARTITIONS |
the window covers more than 4096 partitions, which is what one merge may replace |
SNAPSHOT_COLUMN_RESERVED |
the snapshot column name collides with a publisher column |
SNAPSHOT_IDENTITY_INCOMPLETE |
merge.row_identity does not carry the snapshot column |
SNAPSHOT_PARTITION_MISMATCH |
merge.partition is not the snapshot column with iso_date_value |
SNAPSHOT_PARTITIONS_EXHAUSTED |
the merged relation would hold more days than max_partitions declares |
SNAPSHOT_SPAN_FIXED |
a snapshot covers one day: granularity day, lookback_seconds 0, max_span_seconds 86400 |
SNAPSHOT_BEFORE_START_AT |
the worker read the source on a day before the snapshot’s start_at |
SNAPSHOT_REQUEST_EXCLUSIVE |
the window states both request and snapshot |
SNAPSHOT_SCOPES_UNSUPPORTED |
a snapshot window carries physical_scopes or bootstrap |
SNAPSHOT_RELATION_EMPTY |
the fetch decoded to no rows, which is a fetch that returned nothing rather than a day with nothing in it |
SNAPSHOT_RELATION_TOO_LARGE |
the merged relation is over 2 GiB |
SNAPSHOT_RELATION_TRUNCATED |
a row clamp cut the fetch short, and a snapshot merge writes the whole of its day from that one slice |
SOURCE_PHYSICAL_SCOPE_UNKNOWN |
a binding names a scope the run did not request |
Persist
Section titled “Persist”| Code | Meaning | What the author does |
|---|---|---|
ARTIFACT_PERSIST_FAILED |
the worker could not upload an artifact against Studio’s signed session | retry the run |
RUN_ARTIFACT_SESSION_INVALID |
the artifact session does not match what the worker reported | retry the run |
TABLE_PART_OVER_MAX |
one row group carried a part past the part byte ceiling | narrow the window |
TABLE_PART_MEMORY_CEILING |
the part sink was holding more bytes than its ceiling allows | narrow the window |
TABLE_PART_SCHEMA_DRIFT |
a new part’s schema differs from the version’s | the recipe’s columns changed. Register a revision |
TABLE_MANIFEST_INVALID |
the manifest does not describe the parts | retry |
TABLE_VERSION_UNCOMMITTABLE |
the worker could not commit the version | retry |
TABLE_UPSERT_UNCLUSTERED |
the upsert’s key range intersects too many predecessor parts | use partition_replace, or cluster the table on its row_identity key |
TABLE_FORMAT_UNSUPPORTED |
the table format is not one this worker writes | worker and table disagree |
TABLE_COMPACTION_INVALID |
the compaction request is not applicable | read failure_detail |
Infrastructure
Section titled “Infrastructure”| Code | Raised by | Meaning | What the author does |
|---|---|---|---|
EXECUTION_LOST |
Studio’s lease watchdog | no worker holds this run any more: a crashed process, a preempted job, or an attempt that failed without reporting | re-run it |
EXECUTION_LEASE_EXPIRED |
Studio’s lease watchdog | a worker still claims it and has stopped saying anything | re-run it |
WORKER_TERMINATED |
the worker | something terminated the process | re-run it |
RUN_EXECUTION_FAILED |
the worker | the execution failed with no narrower code | read failure_detail |
RUN_ATTEMPT_INVALID |
the worker | the attempt identity did not check out | retry |
RUN_FENCE_INVALID |
the worker | the fence generation did not check out | retry |
RUN_PREDECESSOR_INVALID |
the worker | the predecessor document is not usable | retry |
RUN_RECORDING_INVALID |
the worker | the named recording is not readable | mr-data stream recordings --document-digest D |
RUN_WATERMARK_INVALID |
the worker | the stream watermark is not the one dispatched | retry |
CLAIM_KIND_UNKNOWN |
the worker | the claim named a kind this worker does not run | worker and Studio disagree |
Cloud HTTP statuses
Section titled “Cloud HTTP statuses”Cloud sits in front of Studio for token exchange and hosts the Public Dataset API. What each status means to the CLI:
| Status | Where | Meaning | What the author does |
|---|---|---|---|
401 |
cloud or Studio | cloud or Studio rejected the device credential or the token | mr-data login |
402 |
cloud | the entitlement check refused | the workspace has no hosted execution access |
403 |
Studio | the token does not carry this authority | check the workspace role |
409 |
Studio | a state conflict, named by the v4 code | read the code |
412 |
Studio | If-Match did not match |
re-read the resource and retry |
413 |
cloud | the artifact or result is too large | narrow the query, or download Parquet |
429 |
cloud or Studio | rate limited | honour Retry-After |
503 |
cloud | cloud’s Studio configuration is incomplete, or Studio stayed unavailable | retry. The CLI retries a 503 that carries a retry window |
Telling which side answered in 60 seconds
Section titled “Telling which side answered in 60 seconds”Read the host first. mostlyright.md (and app., api.) is cloud. A …run.app host is Studio. In a CLI error, /api/auth/* and /api/cli/* are cloud, and /v4/* is Studio.
Read the error’s shape next. problem+json with schema_version: "4.0.0" and an x-correlation-id is Studio v4. {schema_version, error, request_id} is cloud’s Public API v2. A JSON-RPC error.code is cloud’s MCP. A bare THIN_* with no HTTP status is the CLI refusing locally.
Read the run record last. mr-data status RUN_ID --json carries failure_code, failure_detail and failed_stage. A stage from acquire, parse, transform, check, persist with a worker code points at the recipe or the publisher first. EXECUTION_LOST and EXECUTION_LEASE_EXPIRED point at the platform.
Fix a failed run walks the common ones. The numeric bounds behind CLAMP_EXCEEDED, READER_BUDGET and QUERY_TOO_MANY_PARTS are on Limits and ceilings.