usestrix/strix · error · ValueError

Each todo entry must include a non-empty 'title'

Error message

Each todo entry must include a non-empty 'title'

What it means

Thrown when a dict-shaped todo entry has a 'title' that is missing, not a string, or blank after stripping. The title is the only required field per entry; description and priority are optional. Empty string entries from bare strings are silently skipped, but dict entries with empty titles are hard errors.

Source

Thrown at strix/tools/todo/tools.py:220

            return [{"title": entry} for entry in entries]

    if isinstance(data, dict):
        data = [data]
    if not isinstance(data, list):
        raise TypeError("Todos must be provided as a list, dict, or JSON string")

    normalized: list[dict[str, Any]] = []
    for item in data:
        if isinstance(item, str):
            title = item.strip()
            if title:
                normalized.append({"title": title})
            continue
        if not isinstance(item, dict):
            raise TypeError("Each todo entry must be a string or object with a title")
        title = item.get("title", "")
        if not isinstance(title, str) or not title.strip():
            raise ValueError("Each todo entry must include a non-empty 'title'")
        normalized.append(
            {
                "title": title.strip(),
                "description": (item.get("description") or "").strip() or None,
                "priority": item.get("priority"),
            },
        )
    return normalized


def _apply_single_update(
    agent_todos: dict[str, dict[str, Any]],
    todo_id: str,
    title: str | None = None,
    description: str | None = None,
    priority: str | None = None,
    status: str | None = None,
) -> dict[str, Any] | None:

View on GitHub (pinned to 8551339130)

Solutions

  1. Give every todo object a non-empty string 'title': {'title': 'write tests', 'description': '...'}
  2. If the text landed in 'description', move it to 'title'
  3. Strip whitespace when generating titles programmatically and skip blanks

Example fix

# before
todos = [{"description": "refactor auth module"}]

# after
todos = [{"title": "refactor auth module"}]
Defensive patterns

Strategy: validation

Validate before calling

for t in todos:
    if isinstance(t, dict):
        title = t.get("title")
        assert isinstance(title, str) and title.strip(), f"bad title in {t!r}"

Type guard

def has_valid_title(t) -> bool:
    if isinstance(t, str):
        return bool(t.strip())
    return isinstance(t, dict) and isinstance(t.get("title"), str) and bool(t["title"].strip())

Try / catch

try:
    tool.write_todos(todos)
except ValueError as e:
    if "title" in str(e):
        todos = [t if isinstance(t, str) else {**t, "title": t.get("title") or t.get("description") or "untitled"} for t in todos]
        tool.write_todos(todos)

Prevention

When it happens

Trigger: todos=[{'description': 'no title'}], todos=[{'title': ''}], todos=[{'title': 42}] (non-string title), or a title of only whitespace.

Common situations: Agent moving the task text into 'description' and leaving 'title' empty; templating that renders an unset variable as ''; numbers or ids mistakenly placed in title.

Related errors


AI-assisted analysis of usestrix/strix@8551339130 (2026-08-15). Data as JSON: /api/errors/a9705698e27a7270. Report an issue: GitHub.