{"record":{"id":"4df1c40c7f44ba9b","repo":"shareAI-lab/learn-claude-code","slug":"invalid-task-status-task-status-4df1c4","errorCode":null,"errorMessage":"Invalid task status: {task.status}","messagePattern":"Invalid task status: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"s13_agent_teams/code.py","lineNumber":183,"sourceCode":"            f\".{path.name}.{os.getpid()}.{threading.get_ident()}.tmp\"\n        )\n        try:\n            temporary.write_text(\n                json.dumps(asdict(task), indent=2), encoding=\"utf-8\"\n            )\n            os.replace(temporary, path)\n        finally:\n            temporary.unlink(missing_ok=True)\n\n\ndef load_task(task_id: str) -> Task:\n    with task_lock:\n        data = json.loads(_task_path(task_id).read_text(encoding=\"utf-8\"))\n        task = Task(**data)\n        if task.id != task_id:\n            raise ValueError(f\"Task file ID does not match {task_id}\")\n        if task.status not in {\"pending\", \"in_progress\", \"completed\"}:\n            raise ValueError(f\"Invalid task status: {task.status}\")\n        return task\n\n\ndef list_tasks() -> list[Task]:\n    with task_lock:\n        if not TASKS_DIR.exists():\n            return []\n        if not TASKS_ROOT.is_relative_to(WORKDIR.resolve()):\n            raise ValueError(\"Tasks directory escapes workspace\")\n        return [load_task(path.stem)\n                for path in sorted(TASKS_DIR.glob(\"task_*.json\"))]\n\n\ndef get_task(task_id: str) -> str:\n    \"\"\"Return full task details as JSON.\"\"\"\n    task = load_task(task_id)\n    return json.dumps(asdict(task), indent=2)\n","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/shareAI-lab/learn-claude-code/blob/985456f4adea6f4df8fbad4112245dbd97444eae/s13_agent_teams/code.py#L165-L201","documentation":"load_task() enforces a closed status vocabulary: {'pending', 'in_progress', 'completed'}. The Task dataclass annotates status as a bare str, so any other string (or a status written by a newer/older version) is rejected at load time rather than silently flowing into scheduling logic.","triggerScenarios":"Hand-editing .tasks/*.json to 'done', 'Done', 'in-progress' (hyphen), or 'blocked'; a newer version of the system writing a new status like 'failed' that this version doesn't know; serializing an enum instead of its value.","commonSituations":"Manual status edits; version skew between components sharing the .tasks directory; test fixtures written with informal status names.","solutions":["Use exactly one of 'pending', 'in_progress', 'completed' (lowercase, underscore).","Update test fixtures and scripts that write informal statuses like 'done'.","If a new status is genuinely needed, add it to the set in load_task() everywhere the vocabulary is checked."],"exampleFix":"// before\nsave_task(replace_status(task, 'done'))  // next load_task raises\n\n// after\nsave_task(replace_status(task, 'completed'))","handlingStrategy":"validation","validationCode":"VALID_STATUSES = {'pending', 'in_progress', 'completed'}\n\ndef valid_status(status: object) -> bool:\n    return status in VALID_STATUSES","typeGuard":"from typing import Literal, TypeGuard\nTaskStatus = Literal['pending', 'in_progress', 'completed']\n\ndef is_task_status(value: object) -> TypeGuard[TaskStatus]:\n    return value in {'pending', 'in_progress', 'completed'}","tryCatchPattern":"try:\n    task = load_task(task_id)\nexcept ValueError as exc:\n    if 'Invalid task status' in str(exc):\n        log_and_quarantine(task_id)  # move file aside for inspection\n        return None\n    raise","preventionTips":["Use the literal strings 'pending' | 'in_progress' | 'completed'.","Type status as Literal[...] in your own code so typos fail statically.","Validate fixture files' status values in tests."],"tags":["validation","status","data-integrity","load-task"],"backgroundTag":null,"analyzedSha":"985456f4adea6f4df8fbad4112245dbd97444eae","analyzedAt":"2026-08-14T22:02:26.028Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}