shareAI-lab/learn-claude-code · error · ValueError

Task file ID does not match {task_id}

Error message

Task file ID does not match {task_id}

What it means

load_task() reads .tasks/<task_id>.json, constructs Task(**data), and requires the 'id' field inside the JSON to equal the task_id used to locate the file. A mismatch means the file content and filename disagree — manual edits, a botched rename/copy, or two writers racing.

Source

Thrown at s13_agent_teams/code.py:181

        path = _task_path(task.id)
        temporary = path.with_name(
            f".{path.name}.{os.getpid()}.{threading.get_ident()}.tmp"
        )
        try:
            temporary.write_text(
                json.dumps(asdict(task), indent=2), encoding="utf-8"
            )
            os.replace(temporary, path)
        finally:
            temporary.unlink(missing_ok=True)


def load_task(task_id: str) -> Task:
    with task_lock:
        data = json.loads(_task_path(task_id).read_text(encoding="utf-8"))
        task = Task(**data)
        if task.id != task_id:
            raise ValueError(f"Task file ID does not match {task_id}")
        if task.status not in {"pending", "in_progress", "completed"}:
            raise ValueError(f"Invalid task status: {task.status}")
        return task


def list_tasks() -> list[Task]:
    with task_lock:
        if not TASKS_DIR.exists():
            return []
        if not TASKS_ROOT.is_relative_to(WORKDIR.resolve()):
            raise ValueError("Tasks directory escapes workspace")
        return [load_task(path.stem)
                for path in sorted(TASKS_DIR.glob("task_*.json"))]


def get_task(task_id: str) -> str:
    """Return full task details as JSON."""
    task = load_task(task_id)

View on GitHub (pinned to 985456f4ad)

Solutions

  1. Don't clone tasks by copying files; write a small script that loads, changes id, and saves via save_task().
  2. Fix a mismatched file by editing its id field to match the filename (or renaming the file to the embedded id).
  3. Keep all writes going through save_task(), which writes atomically via a temp file and os.replace.

Example fix

# before (broken: copied file)
# .tasks/task_aaaaaaaa.json contains "id": "task_bbbbbbbb"

# after
import json, pathlib
p = pathlib.Path('.tasks/task_aaaaaaaa.json')
data = json.loads(p.read_text())
data['id'] = 'task_aaaaaaaa'
p.write_text(json.dumps(data, indent=2))
Defensive patterns

Strategy: validation

Validate before calling

import json
from pathlib import Path

def task_file_consistent(path: Path) -> bool:
    try:
        return json.loads(path.read_text())['id'] == path.stem
    except (OSError, ValueError, KeyError):
        return False

Try / catch

try:
    task = load_task(task_id)
except ValueError as exc:
    if 'does not match' in str(exc):
        # repair: rewrite file's id to match filename, or drop the corrupt file
        log_corrupt(task_id)
        (TASKS_DIR / f'{task_id}.json').unlink(missing_ok=True)
        return None
    raise

Prevention

When it happens

Trigger: Renaming a task file without editing its id field; copying task_a.json over task_b.json; hand-editing .tasks/*.json; a partial/interleaved write leaving stale content under a new filename.

Common situations: Users duplicating task files to clone tasks; external scripts writing the directory without using save_task(); editor auto-save during a save_task() atomic replace.

Related errors


AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14). Data as JSON: /api/errors/fddc06bf2af4b50f. Report an issue: GitHub.