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().

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.

Appendix: 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)