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

Task subject cannot be empty

Error message

Task subject cannot be empty

What it means

Raised by TaskStore.create() in s10_task_system/code.py:104 when the subject string is empty after strip(). The subject is the task's title and the only human-identifying field on the Task dataclass, so blank subjects are rejected before dependencies are checked or the store directory is created. Whitespace-only strings fail; None fails earlier with AttributeError on .strip().

Source

Thrown at s10_task_system/code.py:104

        return root

    def _path(self, task_id: str, create_root: bool = False) -> Path:
        if not isinstance(task_id, str) or not TASK_ID_PATTERN.fullmatch(task_id):
            raise ValueError(f"Invalid task ID: {task_id!r}")
        root = self._root(create=create_root)
        path = (root / f"{task_id}.json").resolve()
        if not path.is_relative_to(root):
            raise ValueError(f"Invalid task ID: {task_id!r}")
        return path

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

    def create(self, subject: str, description: str = "",
               blocked_by: list[str] | None = None) -> Task:
        subject = subject.strip()
        if not subject:
            raise ValueError("Task subject cannot be empty")

        dependencies = list(dict.fromkeys(blocked_by or []))
        for dependency in dependencies:
            if not self.exists(dependency):
                raise ValueError(f"Dependency not found: {dependency}")

        self._root(create=True)
        for _ in range(100):
            task = Task(
                id=f"task_{secrets.token_hex(4)}",
                subject=subject,
                description=description,
                status="pending",
                owner=None,
                blockedBy=dependencies,
            )
            try:
                with self._path(task.id, create_root=True).open(

View on GitHub (pinned to 985456f4ad)

Solutions

  1. Validate subject.strip() before calling create() and prompt or skip when blank.
  2. When deriving the subject from structured input, fall back to a generated summary (e.g. first line of the description) so it is never empty.
  3. Fix the upstream producer to require a non-empty title.

Example fix

# before
store.create(args.subject or '', description=args.description)

# after
subject = (args.subject or '').strip()
if not subject:
    raise SystemExit('task subject is required')
store.create(subject, description=args.description)
Defensive patterns

Strategy: validation

Validate before calling

def subject_ok(subject) -> bool:
    return isinstance(subject, str) and bool(subject.strip())

Type guard

def is_task_subject(value) -> bool:
    return isinstance(value, str) and len(value.strip()) > 0

Try / catch

try:
    store.create(subject)
except ValueError as e:
    if 'cannot be empty' in str(e):
        raise SystemExit('a task subject is required')
    raise

Prevention

When it happens

Trigger: Calling store.create(' '), store.create(''), or passing a subject built from user/LLM input that reduces to empty after stripping (e.g. a form field left blank, an optional CLI argument defaulting to ''). Description and blocked_by may be empty — only the subject is checked.

Common situations: CLI tools where the subject argument is optional but passed unvalidated; agents creating tasks from parsed requests where the title extraction failed; automated pipelines forwarding empty strings as defaults.

Related errors


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