abhigyanpatwari/GitNexus · error · ValueError

planning must create or modify exactly one plan artifact; ob

Error message

planning must create or modify exactly one plan artifact; observed {len(changed)}

What it means

Thrown by new_plan_doc when the diff of before/after plan digests does not contain exactly one changed path. The harness pins each planning step to produce a single, unambiguous plan artifact; zero changed (planning did nothing observable) or more than one (planning scattered changes) both fail the evidence contract.

Source

Thrown at eval/workflow_bench/runner_artifacts.py:296

                snapshot[path] = hashlib.file_digest(handle, "sha256").hexdigest()
            after = os.fstat(descriptor)
            if (opened.st_size, opened.st_mtime_ns) != (after.st_size, after.st_mtime_ns):
                raise ValueError(f"plan artifact changed while hashing: {path}")
        finally:
            os.close(descriptor)
    return snapshot


def new_plan_doc(worktree: Path, before: dict[Path, str]) -> Path:
    """Return the sole new or modified plan, rejecting ambiguous evidence."""

    after = snapshot_plan_docs(worktree)
    deleted = sorted(path for path in before if path not in after)
    if deleted:
        raise ValueError("planning deleted existing plan artifact(s): " + ", ".join(str(path) for path in deleted))
    changed = sorted(path for path, digest in after.items() if before.get(path) != digest)
    if len(changed) != 1:
        raise ValueError(f"planning must create or modify exactly one plan artifact; observed {len(changed)}")
    return changed[0]


def make_worktree(repo: Path, ref: str, parent: Path) -> Path:
    """Create a self-contained clone per benchmark arm."""

    target = Path(tempfile.mkdtemp(prefix="wfbench-", dir=parent))
    target.rmdir()
    try:
        run_checked(
            [
                "git",
                "clone",
                "--no-local",
                "--no-hardlinks",
                "--no-tags",
                "--quiet",
                str(repo),

View on GitHub (pinned to d540b00184)

Solutions

  1. Confirm the plan is written under the worktree's docs/plans/ as a .md or .html file — other extensions and locations are filtered out by snapshot_plan_docs.
  2. Ensure the planning step produces exactly one new or modified plan file.
  3. If the legitimately created plan is not detected, check it is a regular file (not a symlink) and has a .md/.html suffix.
  4. Merge multiple plan fragments into a single document before the snapshot is taken.

Example fix

// before — agent writes two plan fragments
(docs/plans / 'a.md').write_text(part_a)
(docs/plans / 'b.md').write_text(part_b)

// after — single plan document
(docs/plans / 'plan.md').write_text(part_a + '\n' + part_b)
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
import re

def exactly_one_plan_changed(before, after) -> bool:
    changed = [p for p, d in after.items() if before.get(p) != d]
    return len(changed) == 1

def is_acceptable_plan_path(path: Path) -> bool:
    return path.suffix.lower() in {'.md', '.html'} and path.lstat().st_mode and 0o170000 == 0o100000

Type guard

null

Try / catch

try:
    plan = new_plan_doc(worktree, before)
except ValueError as e:
    if 'exactly one plan artifact' in str(e):
        print('planning produced', e)  # inspect 0 vs N, adjust prompt/paths
        raise
    raise

Prevention

When it happens

Trigger: `changed = sorted(path for path, digest in after.items() if before.get(path) != digest)` has length != 1. Either no plan was created/modified, or several were.

Common situations: Agent wrote plans to a directory other than docs/plans (so zero observed); agent emitted multiple plan files; agent only touched non-plan files; the plan landed as .txt instead of .md/.html and was filtered out by snapshot_plan_docs.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12). Data as JSON: /api/errors/b2834ffa9fdc54fb. Report an issue: GitHub.