shareAI-lab/learn-claude-code · warning · ValueError
Only one todo can be in_progress at a time
Error message
Only one todo can be in_progress at a time
What it means
Raised by TodoManager.update in s05_todo_write/code.py when more than one element has status in_progress after per-item validation. The module enforces a single-active-item invariant so the rendered todo list has exactly one current focus. The count is tallied across the whole submitted list (which replaces, not merges with, existing items), so the error reflects the new list alone.
Source
Thrown at s05_todo_write/code.py:146
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": "[ ]",
"in_progress": "[>]",
"completed": "[x]",
}[todo["status"]]
lines.append(f"{marker} {todo['content']}")
done = sum(todo["status"] == "completed" for todo in self.items)View on GitHub (pinned to 985456f4ad)
Solutions
- Before marking item B in_progress, set item A to completed (or pending) in the same submitted list
- Keep a helper that enforces exactly one in_progress before calling update
- Treat the invariant as intentional: structure plans as a serial focus, not parallel tracks
Example fix
// before
[{"content": "a", "status": "in_progress"}, {"content": "b", "status": "in_progress"}]
// after
[{"content": "a", "status": "completed"}, {"content": "b", "status": "in_progress"}] Defensive patterns
Strategy: validation
Validate before calling
def enforce_single_active(todos):
seen = False
out = []
for t in todos:
s = str(t.get('status', 'pending')).lower()
if s == 'in_progress':
s = 'completed' if seen else 'in_progress'
seen = True
out.append({**t, 'status': s})
return out
TODOS.update(enforce_single_active(todos)) Type guard
def single_in_progress(todos: list) -> bool:
return sum(1 for t in todos if str(t.get('status', '')).lower() == 'in_progress') <= 1 Prevention
- Demote the previous active item in the same replacement list
- Check the invariant client-side before update
- Model work as a serial focus, one active step at a time
When it happens
Trigger: Submitting [{..."in_progress"}, {..."in_progress"}] — e.g. marking a second item active without first demoting the previous one to pending/completed in the same replacement list.
Common situations: Agents starting a new step while forgetting to close the previous one; parallel-work plans where the model wants two active items; appending an in_progress item to a list that already contains one.
Related errors
- Item {i}: content required
- Item {i}: invalid status '{status}'
- 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/d0334f23bb89e3a8.
Report an issue: GitHub.