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

Raised by TaskStore.load() in s10_task_system/code.py:141 when the JSON file at {task_id}.json parses and constructs a Task, but the Task's own id field differs from the task_id used to locate the file. The filename and the embedded id must agree; a mismatch means the file was renamed, hand-edited, or copied from another task. The check runs before the status check, and save() always writes a matching pair, so mismatched files come from external modification.

Source

Thrown at s10_task_system/code.py:141

                    "x", encoding="utf-8"
                ) as handle:
                    json.dump(asdict(task), handle, indent=2)
                return task
            except FileExistsError:
                continue
        raise RuntimeError("Could not allocate a unique task ID")

    def save(self, task: Task) -> None:
        self._path(task.id, create_root=True).write_text(
            json.dumps(asdict(task), indent=2),
            encoding="utf-8",
        )

    def load(self, task_id: str) -> Task:
        data = json.loads(self._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(self) -> list[Task]:
        if not self.directory.exists():
            return []
        root = self._root()
        return [self.load(path.stem)
                for path in sorted(root.glob("task_*.json"))]


TASKS = TaskStore(TASKS_DIR)


def create_task(subject: str, description: str = "",
                blockedBy: list[str] | None = None) -> Task:
    return TASKS.create(subject, description, blockedBy)

View on GitHub (pinned to 985456f4ad)

Solutions

  1. Restore agreement: either rename the file back to {task.id}.json or edit the JSON's id to equal the filename's stem.
  2. Duplicate tasks via store.create() + save(task with replace(id=...)) rather than by copying files.
  3. In migration scripts, always write both the filename and the embedded id from the same source.
Defensive patterns

Strategy: validation

Validate before calling

import json
from pathlib import Path

def file_matches_id(store_dir: Path, task_id: str) -> bool:
    p = store_dir / f'{task_id}.json'
    if not p.is_file():
        return False
    return json.loads(p.read_text()).get('id') == task_id

Try / catch

try:
    task = store.load(task_id)
except ValueError as e:
    if 'does not match' in str(e):
        # heal: rewrite the embedded id, or rename the file
        heal_task_file(store.directory, task_id)
        task = store.load(task_id)
    else:
        raise

Prevention

When it happens

Trigger: Renaming .tasks/task_aaaa1111.json to task_bbbb2222.json and calling load('task_bbbb2222'); editing the JSON in a text editor and changing the id field; copying a task file as a template and forgetting to update both the filename and the id; merging stores by hand.

Common situations: Manual 'duplicate this task' workflows done in the file manager; version-control conflicts resolved by keeping one file under another's name; migration scripts that rewrite ids but not filenames (or vice versa).

Related errors


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