Documentation / VFX-E-1502

VFX-E-1502

Title

RunNotRecorded

Explanation

run_suite records every run in the run registry before it spawns anything: the run is written as running, and the registry — not the caller — decides where that run's JSON Lines events file will live. When the server was started with --workspace <path>, that record is a real file on disk, <root>/.vouchfx/runs/<runId>/run.json, created together with the run's own directory.

This code means that write failed. The output directory could not be created, the metadata document could not be written, or its atomic publish (a rename over the final name) was refused. Nothing was run: the failure happens before the CLI handshake and before any process is spawned, so no container was started, no suite was executed, and no verdict exists.

There are two producers, one step apart in the same directory. The first is the registry write described above. The second is the run lock: before recording anything, run_suite claims <root>/.vouchfx/runs/.lock, and when that claim cannot be evaluated at all — as opposed to being held by another run, which is VFX-E-1501 — the same code is reported. That is deliberate rather than a shortcut: .lock and <runId>/run.json live under the one directory, so a condition that refuses the lock is the same condition that would refuse the registry write a moment later, observed one step earlier. It is reported here rather than as VFX-E-1501 because a host told "another run is in progress" would poll a location that will never accept a run.

Because the lock is one of the producers, the thing at <root>/.vouchfx/runs/.lock is worth inspecting directly: a directory created there by mistake, or a symbolic link/junction planted there, will each wedge every run in that workspace. The server refuses to open a link at that path outright — following one would let whatever it points at be held open exclusively, or created outright if the link dangles — so a link there produces this code on every call until it is removed.

A third producer, rare but not hypothetical: the entry is too large to be readable. The registry refuses to write a metadata document larger than the 64 KB a reader will accept, because writing one would record the run and then make it permanently invisible — explain_run's default would skip past it, and so would any listing, while the run itself proceeded normally. The tool-level bounds on paths and labels are character counts, and JSON escaping turns each non-ASCII character into a six-byte \uXXXX sequence, so a run whose suite paths or labels are largely non-ASCII can serialise past the byte cap while sitting comfortably inside every character bound. Nothing is run, and the fix is to name fewer suites (or shorter labels) in the call rather than to retry it.

A read-only file at that path is not one of these cases and has not been since the lock was narrowed to open the file for reading only: the claim itself comes from the exclusive share mode, not from write access, so a read-only .lock is opened, locked, and released exactly like any other (measured on Windows and Linux). Nothing about a read-only lock file needs clearing.

It is deliberately not reported as a run verdict. An Inconclusive result would claim a run was attempted and reached no conclusion; here the run never began at all, and the honest shape for "this server could not do its own bookkeeping" is a tool error.

retryable is true, which is unusual for a filesystem-flavoured error in this catalogue and is a statement about the cause rather than about the call: every producer is a storage-availability condition on a directory the operator configured — a full volume, a lock, a directory that has not been provisioned yet. Those clear on their own, and the identical call then succeeds with nothing about it changed. (Contrast VFX-E-1003, which is not retryable precisely because it cannot tell a momentary lock from a permanent permission problem.) A genuinely read-only workspace root will, however, produce this same message on every retry — that is the signal to fix the root rather than to keep retrying.

Without --workspace, the registry is in-memory and writes nothing anywhere, so this code cannot be produced by a server running in that mode.

Common causes

  • The workspace root is on a read-only mount, or the account running the server has no write permission under <root>/.vouchfx/.
  • The volume holding the workspace root is full, or has exhausted its inode/quota allowance.
  • <root>/.vouchfx (or <root>/.vouchfx/runs) exists as a file rather than a directory, so the run directory cannot be created beneath it.
  • Something is planted at <root>/.vouchfx/runs/.lock that the run lock will not open — a directory of that name, or a symbolic link/junction (links are refused outright, never followed). A read-only file there is fine and does not produce this code.
  • An antivirus or file-sync agent holds a transient lock on the run directory or its metadata document at the moment of the atomic publish.
  • The workspace root was deleted or unmounted after the server started, so the path it resolved at startup no longer exists.
  • The run's own metadata serialises past 64 KB — many long, largely non-ASCII suite paths and/or labels, whose JSON-escaped form is six bytes per character. Retrying is not the fix here; naming fewer or shorter suites and labels is.

Fixes

  • Retry the identical call once — a full volume, a sync-agent lock, or a momentary contention clears on its own, and this error is marked retryable for exactly that case.
  • Check free space on the volume holding the workspace root, and free some if it is exhausted.
  • Confirm the account running vouchfx-mcp can create directories and files under <root>/.vouchfx/runs/; the run registry is the only thing this server writes there.
  • Confirm <root>/.vouchfx and <root>/.vouchfx/runs are directories (or absent, so the server can create them) rather than files left behind by something else.
  • Inspect <root>/.vouchfx/runs/.lock itself: it must be an ordinary file (read-only is fine) or absent. A directory of that name, or a link (symbolic link or junction) planted there, wedges every run in the workspace and produces this code on each attempt; remove it and retry.
  • If the workspace root is read-only by design, start the server without --workspace; the registry is then in-memory, nothing is written, and explain_run falls back to its session-scoped behaviour.
  • If the root was moved or unmounted, restart the server so it resolves the workspace afresh — the root is resolved once at startup and is not re-probed per call.