shareAI-lab/learn-claude-code · warning · ValueError
Max 20 todos
Error message
Max 20 todos
What it means
Raised by TodoManager.update in s_full.py when the validated list contains more than 20 items. The cap is a hard limit applied after per-item validation, forcing the caller to keep plans compact. The whole update is atomic: the error means self.items still holds the previous list.
Source
Thrown at agents/s_full.py:139
# === SECTION: todos (s03) ===
class TodoManager:
def __init__(self):
self.items = []
def update(self, items: list) -> str:
validated, ip = [], 0
for i, item in enumerate(items):
content = str(item.get("content", "")).strip()
status = str(item.get("status", "pending")).lower()
af = str(item.get("activeForm", "")).strip()
if not content: raise ValueError(f"Item {i}: content required")
if status not in ("pending", "in_progress", "completed"):
raise ValueError(f"Item {i}: invalid status '{status}'")
if not af: raise ValueError(f"Item {i}: activeForm required")
if status == "in_progress": ip += 1
validated.append({"content": content, "status": status, "activeForm": af})
if len(validated) > 20: raise ValueError("Max 20 todos")
if ip > 1: raise ValueError("Only one in_progress allowed")
self.items = validated
return self.render()
def render(self) -> str:
if not self.items: return "No todos."
lines = []
for item in self.items:
m = {"completed": "[x]", "in_progress": "[>]", "pending": "[ ]"}.get(item["status"], "[?]")
suffix = f" <- {item['activeForm']}" if item["status"] == "in_progress" else ""
lines.append(f"{m} {item['content']}{suffix}")
done = sum(1 for t in self.items if t["status"] == "completed")
lines.append(f"\n({done}/{len(self.items)} completed)")
return "\n".join(lines)
def has_open_items(self) -> bool:
return any(item.get("status") != "completed" for item in self.items)
View on GitHub (pinned to 985456f4ad)
Solutions
- Consolidate related steps into broader items so the list stays at or under 20
- Split work into phases and replace the list per phase rather than accumulating items
- Check len(items) <= 20 before calling update and trim/merge client-side
Example fix
// before TODOS.update(items) # items has 23 entries // after merged = merge_related_steps(items) # <= 20 entries TODOS.update(merged)
Defensive patterns
Strategy: validation
Validate before calling
if len(items) > 20:
items = merge_related_steps(items)[:20] # or split into phases
TODOS.update(items) Prevention
- Set maxItems: 20 in the tool schema
- Replace the todo list per phase instead of accumulating
- Prefer fewer, broader todos over many granular ones
When it happens
Trigger: Submitting 21+ todo items in one update() call, e.g. an agent decomposing a large task into one item per subtask and exceeding the cap by a single item.
Common situations: Over-granular planning (one todo per file instead of per feature); appending new steps to an existing 20-item list instead of replacing it; migrating a long external checklist into the todo tool verbatim.
Related errors
- Max 20 todos allowed
- Item {i}: content required
- Item {i}: invalid status '{status}'
- todos must be a list or JSON array string
- todos[{index}] requires content
AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14).
Data as JSON: /api/errors/68039f17af823d63.
Report an issue: GitHub.