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

Invalid task ID: {task_id!r}

Error message

Invalid task ID: {task_id!r}

What it means

_task_path() validates a task ID before mapping it to a file under the tasks directory. This first raise fires when task_id is not a str or fails TASK_ID_PATTERN.fullmatch — i.e. the ID is malformed (wrong shape, bad characters) before any filesystem resolution happens. All task APIs (create/load/save/get_task_json/can_start) funnel through this guard.

Source

Thrown at s15_integrated_harness/code.py:200

        finally:
            if team is not None:
                team.release()


@dataclass
class Task:
    id: str
    subject: str
    description: str
    status: str
    owner: str | None
    blockedBy: list[str]
    worktree: str | None = None


def _task_path(task_id: str) -> Path:
    if not isinstance(task_id, str) or not TASK_ID_PATTERN.fullmatch(task_id):
        raise ValueError(f"Invalid task ID: {task_id!r}")
    path = (TASKS_DIR / f"{task_id}.json").resolve()
    if (not TASKS_ROOT.is_relative_to(WORKDIR.resolve())
            or not path.is_relative_to(TASKS_ROOT)):
        raise ValueError(f"Invalid task ID: {task_id!r}")
    return path


def create_task(subject: str, description: str = "",
                blockedBy: list[str] | None = None) -> Task:
    subject = subject.strip()
    if not subject:
        raise ValueError("Task subject cannot be empty")
    dependencies = list(dict.fromkeys(blockedBy or []))
    with task_store_lock():
        for dependency in dependencies:
            if not _task_path(dependency).is_file():
                raise ValueError(f"Dependency not found: {dependency}")
        for _ in range(100):

View on GitHub (pinned to 985456f4ad)

Solutions

  1. Generate IDs only via create_task() (format task_ + 8 hex chars, e.g. task_1a2b3c4d) and pass those verbatim.
  2. Sanitize caller input against the same pattern (regex like r'task_[0-9a-f]{8}') before invoking task APIs.
  3. If you changed TASK_ID_PATTERN, regenerate/rewrite existing task JSON filenames to match.

Example fix

// before
load_task(user_supplied_id)  // raises ValueError: Invalid task ID

// after
import re
TASK_ID_RE = re.compile(r"task_[0-9a-f]{8}")
if not isinstance(user_supplied_id, str) or not TASK_ID_RE.fullmatch(user_supplied_id):
    return f"Error: malformed task ID {user_supplied_id!r}"
task = load_task(user_supplied_id)
Defensive patterns

Strategy: validation

Validate before calling

import re

TASK_ID_RE = re.compile(r"task_[0-9a-f]{8}")

def is_valid_task_id(task_id) -> bool:
    return isinstance(task_id, str) and bool(TASK_ID_RE.fullmatch(task_id))

Type guard

def is_task_id(value) -> bool:
    return isinstance(value, str) and bool(__import__('re').fullmatch(r'task_[0-9a-f]{8}', value))

Try / catch

try:
    task = load_task(task_id)
except ValueError as e:
    if "Invalid task ID" in str(e):
        return f"Error: {e}"  # surface to model/user, do not retry
    raise

Prevention

When it happens

Trigger: Calling load_task/save_task/create_task dependencies with values like None, an int, 'task_abc' not matching the pattern, IDs containing slashes or '../', or empty strings. Also model-generated tool calls passing unvalidated IDs from conversation text.

Common situations: An LLM tool call hallucinating a task ID format; passing a file stem with whitespace; passing a Path object instead of str; IDs from an older format after the pattern was tightened.

Related errors


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