Common failures
Current runs record lifecycle transitions in
.loom/.runtime/runs/<run_id>/state.jsonl and contextual output and diagnostics
in the adjacent events.jsonl. Start with loom logs <run_id> --state, then
read loom logs <run_id> --json for the failed operation's IDs. MCP clients can
use loom_read_run for states and loom_read_events with job_id or stream filters.
Match the error to a failure class, then follow the suggested check.
Not sure where to start? Begin with the Diagnostics ladder.
Schema validation failures (workflow YAML)
| Symptom | loom check or loom run exits non-zero with "schema validation" errors referencing unknown fields, wrong types, or missing required keys. |
| Root cause | Workflow YAML does not match the expected schema version (field name, nesting, or type). |
| First step | Fix the first reported error — later errors are often cascading. |
loom check
Cross-reference the exact field name and type against Workflow schema v1. If the error only reproduces during execution, verify you are running loom check from the repo that contains .loom/workflow.yml and compare that file with any alternate path you pass to loom run.
Example error signatures (from schema validation tests):
WF_SCHEMA_V1 /include/0/local: set include.local to a normalized repository-relative .yml or .yaml path
WF_SCHEMA_V1 /.a/extends: resolve extends cycle by removing one extends edge: .a -> .b -> .a
See also: Syntax v1 · loom check · loom run
Docker provider issues (jobs using image:)
| Symptom | Jobs with image: fail to start, hang at startup, or fail during pull. Errors mention "cannot connect to Docker", "pull access denied", "no such image", or "exec format error". |
| Root cause | Docker is not running or not reachable, the provider backend does not match your environment, or there is an image pull / auth / platform mismatch (e.g. arm64 vs amd64). |
| First step | Verify Docker is reachable from the shell where you run Loom. |
docker version
docker info
If Docker is reachable, confirm which workspace mount mode Loom is using:
| Method | Example |
|---|---|
| CLI flag | --docker-workspace-mount bind_mount or --docker-workspace-mount ephemeral_volume |
| Environment variable | LOOM_DOCKER_WORKSPACE_MOUNT=bind_mount |
Read loom logs <run_id> --state --json for the failed job and its error field. Then inspect
events.jsonl messages with that job_id; provider preparation can fail before
any command starts. MCP loom_read_events can select the job directly.
Example provider failure (from Docker provider tests):
Cannot connect to the Docker daemon at unix:///var/run/docker.sock.
See also: Docker provider · loom run · Diagnostics ladder
Cache divergence quarantine (--cache-diff)
| Symptom | A run with --cache-diff reports divergence and quarantines cache-hit keys (or refuses to trust a previously cached result). |
| Root cause | Loom detected a correctness risk: a cached result does not match a recomputation. Common causes include nondeterministic scripts, untracked inputs, environment drift, or tool version changes. |
| First step | Treat this as a correctness signal, not "cache being flaky". Localize where divergence was detected. |
Read the final workflow error in state.jsonl and the divergence diagnostic in
events.jsonl. The cache-on execution uses the printed <run_id> directory;
the cache-off baseline uses <run_id>-baseline-cache-off. Both directories
contain the same two recording files. Quarantine entries, when present, are
stored in .loom/.runtime/cache/v1/quarantine.json.
A comparison can report divergence even when both executions succeeded. Compare the recorded job outcomes and declared output files, and review changed inputs, tool versions and external state before changing keys or clearing quarantine. The two-file recording does not contain a structured comparison report.
See also: Cache concept · Cache workflow · loom run
Variable precedence surprises (unexpected values)
| Symptom | A command behaves as if a variable has a different value than expected — wrong branch, wrong token, wrong flags. You set it in the workflow, but the step sees something else. |
| Root cause | Multiple layers provide values (predefined, workflow, default, job, provider, or command-local variables), and a later layer overrides an earlier one. |
| First step | Inspect what the failing step actually received — do not reason from memory. |
Loom does not currently emit a dedicated "effective env" artifact. Add a temporary diagnostic line to your workflow to capture the resolved environment:
script:
- env | grep -E '^CI_|^LOOM_|^YOURPREFIX_' | sort
- <your real command>
Read loom logs <run_id> --json and locate events with the diagnostic command's
job_id, step_id, command_id and stream: "stdout". Their message fields
contain the printed output. MCP loom_read_events supports job_id and stream
filters. Print only the nonsecret values needed for this diagnosis.
Compare the resolved value with the variable precedence rules. Host jobs also inherit the process environment; Docker jobs receive declared and predefined variables plus image defaults. Command-local assignments affect only the command they prefix.
See also: Variables concept · Variables workflow · loom run
Secrets resolution failures (SECRETS_*)
| Symptom | A job fails before or during script execution with a SECRETS_* error code. |
| Root cause | The secret reference cannot be resolved — provider unavailable, ref malformed, entry missing, or required secret absent. |
| First step | Read the error code from CLI output or job events, then match it to the table below. |
| Code | Meaning | Fix |
|---|---|---|
SECRETS_PROVIDER_UNAVAILABLE | Provider unreachable, misconfigured, or authentication failed | Check the provider's configuration, credentials, and availability |
SECRETS_REF_INVALID | Malformed or unsupported ref URI | Fix the ref value — check scheme and syntax |
SECRETS_REF_NOT_FOUND | Provider resolved but entry/field does not exist | Verify env var is exported (env://) or entry path is correct (keepass://) |
SECRETS_REQUIRED_MISSING | Required secret could not be resolved | Export the env var, or set required: false if the secret is optional |
SECRETS_UNSAFE_DEBUG_TRACE | CI_DEBUG_TRACE=true with file: false secrets | Disable debug trace, or switch secrets to file: true |
Find the failed job in loom logs <run_id> --state, then read its diagnostic
messages in events.jsonl with the same job_id. Search message and state
error text for the SECRETS_* code and any available provider or secret-name
context. Known exact secret values are masked before recording; review excerpts
before sharing them.
Example — required env-based secret where the var is not exported:
SECRETS_REQUIRED_MISSING: secret "DEPLOY_TOKEN" (env://DEPLOY_TOKEN) could not be resolved
Fix: export DEPLOY_TOKEN="your-value" before running Loom.
See also: Secrets error codes · Concepts → Secrets · Workflows → Secrets
Cannot locate the failing operation
Read the state records before widening the output excerpt:
loom logs <run_id> --state
loom logs <run_id> --tail 30
loom logs <run_id> --json
Find the failed kind and its job_id, step_id and command_id when present.
Match those IDs in event records. A provider failure can have a job ID without
a command ID because the command never started. An interrupted run may lack a
terminal state; use its last recorded states and events.
MCP loom_read_run returns all states. loom_read_events can filter by exact
job_id and stream; tail and max_lines select a smaller excerpt. It returns
total_events before limiting. Set max_lines to that total to read all matches.
See Diagnostics ladder and Runtime logs.
Still stuck?
- Follow the full diagnostic flow: Diagnostics ladder
- Prepare a minimal report: What to share
- Include in your report:
- The exact command you ran (including flags)
- The run ID and relevant job, step and command IDs
- The relevant
state.jsonlrecords and a short reviewedevents.jsonlexcerpt - The validation receipt for a
loom checkfailure, when available