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

Invalid task status: {task.status}

Error message

Invalid task status: {task.status}

What it means

load_task() enforces a closed set of statuses: pending, in_progress, completed. Any other value in the JSON file is rejected because downstream logic (can_start, assignment leasing, completion release) switches on exactly these states; an unknown status would make scheduling undefined.

Source

Thrown at s15_integrated_harness/code.py:258

            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_json(task_id: str) -> str:
    return json.dumps(asdict(load_task(task_id)), indent=2)


def can_start(task_id: str) -> bool:

View on GitHub (pinned to 985456f4ad)

Solutions

  1. Use only the three canonical statuses; transition tasks via the harness's claim/complete APIs, not file edits.
  2. If migrating, map external statuses onto {pending, in_progress, completed} before writing.
  3. Fix any offending files in TASKS_DIR with a one-off script that rewrites non-canonical statuses.

Example fix

// before
{"id": "task_0a1b2c3d", "status": "done", ...}

// after
{"id": "task_0a1b2c3d", "status": "completed", ...}
Defensive patterns

Strategy: validation

Validate before calling

VALID_STATUSES = {"pending", "in_progress", "completed"}

def has_valid_status(task: dict) -> bool:
    return task.get("status") in VALID_STATUSES

Type guard

def is_task_status(value) -> bool:
    return value in {"pending", "in_progress", "completed"}

Try / catch

try:
    task = load_task(task_id)
except ValueError as e:
    if "Invalid task status" in str(e):
        # rewrite the file's status to a canonical value or quarantine it
        raise

Prevention

When it happens

Trigger: A task JSON containing "status": "done", "blocked", "failed", capitalized variants, or a typo; hand-edited files; a writer from an older/newer version of the harness with a different status vocabulary.

Common situations: Manual edits 'marking a task done'; scripts migrating tasks from another tracker that uses different status names; version drift after the status enum changed.

Related errors


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