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

Item {i}: invalid status '{status}'

Error message

Item {i}: invalid status '{status}'

What it means

Raised by TodoManager.update in s_full.py when an item's status (lowercased string of item.get('status', 'pending')) is not one of pending/in_progress/completed. The value is coerced with str() before comparison, so non-string statuses like booleans or ints also fail after coercion ('true', '1'). The failing index i and the bad value are both included in the message.

Source

Thrown at agents/s_full.py:135

        return f"Edited {path}"
    except Exception as e:
        return f"Error: {e}"


# === 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)

View on GitHub (pinned to 985456f4ad)

Solutions

  1. Map your statuses to the allowed set before update: {'done': 'completed', 'doing': 'in_progress', 'todo': 'pending'}
  2. Validate with status in ('pending', 'in_progress', 'completed') client-side and reject early
  3. Note that casing is tolerated (values are lowercased) but word separators are not — use snake_case

Example fix

// before
TODOS.update([{"content": "x", "status": "done", "activeForm": ""}])
// after
TODOS.update([{"content": "x", "status": "completed", "activeForm": ""}])
Defensive patterns

Strategy: validation

Validate before calling

ALLOWED = ('pending', 'in_progress', 'completed')
MAP = {'done': 'completed', 'todo': 'pending', 'doing': 'in_progress', 'inprogress': 'in_progress'}

items = [{**it, 'status': MAP.get(str(it.get('status', 'pending')).lower(), str(it.get('status', 'pending')).lower())} for it in items]
assert all(it['status'] in ALLOWED for it in items)
TODOS.update(items)

Type guard

def is_valid_status(s: object) -> bool:
    return str(s if s is not None else 'pending').lower() in ('pending', 'in_progress', 'completed')

Try / catch

try:
    TODOS.update(items)
except ValueError as e:
    m = re.search(r"invalid status '(.*?)'", str(e))
    if m:
        fixed = MAP.get(m.group(1))
        if fixed:
            items = [{**it, 'status': fixed} if str(it['status']).lower() == m.group(1) else it for it in items]
            TODOS.update(items)
        else:
            raise
    else:
        raise

Prevention

When it happens

Trigger: Passing status "done", "in-progress" (hyphen), "In Progress" (this one actually works because of .lower(), but "in progress" with a space fails), status True (coerces to "true"), or status 2. Each produces the message with the coerced string shown.

Common situations: LLMs writing natural-language statuses like "done" or "in review"; camelCase "inProgress" (lowercases to "inprogress", still invalid); enum values copied from a different todo system's schema.

Related errors


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