shareAI-lab/learn-claude-code · error · ValueError
todos[{index}] has invalid status '{status}'
Error message
todos[{index}] has invalid status '{status}' What it means
Raised by TodoManager.update in s05_todo_write/code.py when a todo's status (string-coerced and lowercased) is not pending, in_progress, or completed. The invalid value is echoed in the message. Statuses are normalized with str().lower(), so casing is forgiven but any other wording, separator style, or non-string type fails.
Source
Thrown at s05_todo_write/code.py:140
raise ValueError("todos must be a list or JSON array string") from e
if not isinstance(todos, list):
raise ValueError("todos must be a list")
if len(todos) > 20:
raise ValueError("Max 20 todos allowed")
validated = []
in_progress_count = 0
for index, todo in enumerate(todos):
if not isinstance(todo, dict):
raise ValueError(f"todos[{index}] must be an object")
content = str(todo.get("content", "")).strip()
status = str(todo.get("status", "pending")).lower()
if not content:
raise ValueError(f"todos[{index}] requires content")
if status not in ("pending", "in_progress", "completed"):
raise ValueError(f"todos[{index}] has invalid status '{status}'")
if status == "in_progress":
in_progress_count += 1
validated.append({"content": content, "status": status})
if in_progress_count > 1:
raise ValueError("Only one todo can be in_progress at a time")
self.items = validated
return self.render()
def render(self) -> str:
if not self.items:
return "No todos."
lines = []
for todo in self.items:
marker = {
"pending": "[ ]",View on GitHub (pinned to 985456f4ad)
Solutions
- Map external statuses to the allowed trio before calling (done->completed, doing->in_progress)
- Validate status in ('pending','in_progress','completed') client-side and correct early
- Remember casing is tolerated but the exact snake_case words are required
Example fix
// before
{"content": "ship", "status": "done"}
// after
{"content": "ship", "status": "completed"} Defensive patterns
Strategy: validation
Validate before calling
ALLOWED = ('pending', 'in_progress', 'completed')
MAP = {'done': 'completed', 'todo': 'pending', 'doing': 'in_progress'}
for t in todos:
s = str(t.get('status', 'pending')).lower()
t['status'] = MAP.get(s, s)
assert all(t['status'] in ALLOWED for t in todos)
TODOS.update(todos) Type guard
def is_allowed_status(s: object) -> bool:
return str(s).lower() in ('pending', 'in_progress', 'completed') Try / catch
try:
TODOS.update(todos)
except ValueError as e:
m = re.search(r"invalid status '(.*?)'", str(e))
if m and m.group(1) in MAP:
fixed = MAP[m.group(1)]
todos = [{**t, 'status': fixed} if str(t['status']).lower() == m.group(1) else t for t in todos]
TODOS.update(todos)
else:
raise Prevention
- Use an enum of exactly the three statuses in the schema
- Normalize natural-language statuses via a mapping table
- Casing is forgiven; wording and separators are not
When it happens
Trigger: status: "done", "in-progress", "inprogress", "blocked", "todo", True (coerces to "true"), or 1 (coerces to "1").
Common situations: Agents using natural words like done/blocked; camelCase "inProgress" lowercasing to "inprogress" which still fails; statuses imported from an external tracker with a richer enum.
Related errors
- Item {i}: invalid status '{status}'
- Item {i}: content required
- Max 20 todos
- todos must be a list or JSON array string
- Max 20 todos allowed
AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14).
Data as JSON: /api/errors/3e879a10a264954b.
Report an issue: GitHub.