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

Invalid status: {status}

Error message

Invalid status: {status}

What it means

Raised by update() in agents/s12_worktree_task_isolation.py:175 when the status argument is truthy but outside {pending, in_progress, completed}. Same closed status set as s07 and also case-sensitive (no lowercasing), so "Completed" or "done" fail. On valid transitions the method also stamps updated_at.

Source

Thrown at agents/s12_worktree_task_isolation.py:175

            "blockedBy": [],
            "created_at": time.time(),
            "updated_at": time.time(),
        }
        self._save(task)
        self._next_id += 1
        return json.dumps(task, indent=2)

    def get(self, task_id: int) -> str:
        return json.dumps(self._load(task_id), indent=2)

    def exists(self, task_id: int) -> bool:
        return self._path(task_id).exists()

    def update(self, task_id: int, status: str = None, owner: str = None) -> str:
        task = self._load(task_id)
        if status:
            if status not in ("pending", "in_progress", "completed"):
                raise ValueError(f"Invalid status: {status}")
            task["status"] = status
        if owner is not None:
            task["owner"] = owner
        task["updated_at"] = time.time()
        self._save(task)
        return json.dumps(task, indent=2)

    def bind_worktree(self, task_id: int, worktree: str, owner: str = "") -> str:
        task = self._load(task_id)
        task["worktree"] = worktree
        if owner:
            task["owner"] = owner
        if task["status"] == "pending":
            task["status"] = "in_progress"
        task["updated_at"] = time.time()
        self._save(task)
        return json.dumps(task, indent=2)

View on GitHub (pinned to 985456f4ad)

Solutions

  1. Use exactly "pending", "in_progress", "completed"
  2. Normalize at the call site: status.strip().lower() and map "done"->"completed"
  3. Do not rely on status="" to mean pending — it means 'leave unchanged'

Example fix

# before
tasks.update(task_id=4, status="In_Progress")
# ValueError: Invalid status: In_Progress

# after
status = "in_progress"
tasks.update(task_id=4, status=status)
Defensive patterns

Strategy: validation

Validate before calling

VALID = {"pending", "in_progress", "completed"}
status = status.strip().lower() if isinstance(status, str) else None
status = {"done": "completed"}.get(status, status)
assert status is None or status in VALID, f"Invalid status: {status}; allowed {sorted(VALID)}"

Type guard

WORKTREE_STATUSES = frozenset(("pending", "in_progress", "completed"))

def is_valid_worktree_status(s: object) -> bool:
    return s is None or (isinstance(s, str) and s in WORKTREE_STATUSES)  # case-sensitive; '' means unchanged

Try / catch

try:
    TASKS.update(task_id, status)
except ValueError as e:
    if "Invalid status" in str(e):
        return f"Tool error: {e}. Allowed: pending, in_progress, completed (exact, lowercase)."
    raise

Prevention

When it happens

Trigger: task_update with status "done", "cancelled", "blocked", "In_Progress", or any free-text value. Passing status="" is falsy and silently skips the check (no error, no change) — a quieter trap worth knowing.

Common situations: Models abbreviating to "done". Passing user-facing strings unnormalized. Expecting cancelled/blocked states that the worktree task schema does not have.

Related errors


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