can1357/oh-my-pi · error · ValueError
todo_phases.toml[{task_kind!r}] must be a list of phases
Error message
todo_phases.toml[{task_kind!r}] must be a list of phases What it means
`seed_phases(task_kind)` loads `todo_phases.toml`, reads the `task_kind` key, and requires its value to be a list of phase tables. When the value under that key exists but is not a list (string, integer, or bare table), it raises ValueError with the offending key quoted. A missing key returns [] without error — only a present-but-wrong-typed value triggers this message.
Source
Thrown at python/robomp/src/persona.py:75
return data
def _require_mapping(value: Any, context: str) -> Mapping[str, Any]:
if not isinstance(value, Mapping):
raise ValueError(f"{context} must be a table")
return value
def _require_nonempty_str(value: Any, context: str) -> str:
if not isinstance(value, str) or not value.strip():
raise ValueError(f"{context} must be a non-empty string")
return value
def seed_phases(task_kind: str) -> list[dict[str, Any]]:
raw_phases = _load_toml("todo_phases.toml").get(task_kind, [])
if not isinstance(raw_phases, list):
raise ValueError(f"todo_phases.toml[{task_kind!r}] must be a list of phases")
phases: list[dict[str, Any]] = []
for phase_index, raw_phase in enumerate(raw_phases):
phase = _require_mapping(raw_phase, f"todo_phases.toml[{task_kind!r}][{phase_index}]")
name = _require_nonempty_str(
phase.get("name"),
f"todo_phases.toml[{task_kind!r}][{phase_index}].name",
)
raw_tasks = phase.get("tasks")
if not isinstance(raw_tasks, list) or not raw_tasks:
raise ValueError(f"todo_phases.toml[{task_kind!r}][{phase_index}].tasks must be a non-empty list")
tasks = [
_require_nonempty_str(
task,
f"todo_phases.toml[{task_kind!r}][{phase_index}].tasks[{task_index}]",
)
for task_index, task in enumerate(raw_tasks)
]View on GitHub (pinned to 9690622007)
Solutions
- Confirm the value type: `python -c "import tomllib; print(type(tomllib.load(open('todo_phases.toml','rb'))['bug']))"` must be list
- Rewrite the entry as an array of tables: `bug = [{ name = "reproduce", tasks = ["...", "..."] }, ...]` or `[[todo_phases.bug]]` blocks
- Restore the original file if a merge broke it: `git checkout -- python/robomp/src/prompts/todo_phases.toml`
- Restart the process after fixing — `_load_toml` results are `@cache`d for the process lifetime
Example fix
# before (todo_phases.toml)
[todo_phases]
bug = "reproduce then fix"
# after
[todo_phases]
bug = [{ name = "reproduce", tasks = ["write failing repro", "confirm failure"] }, { name = "fix", tasks = ["patch", "run tests"] }] Defensive patterns
Strategy: validation
Validate before calling
import tomllib
phases = tomllib.load(open("todo_phases.toml", "rb")).get("bug")
if phases is not None:
assert isinstance(phases, list), "todo_phases[bug] must be a list"
for i, ph in enumerate(phases):
assert isinstance(ph, dict) and ph.get("name") and ph.get("tasks"), f"phase {i} malformed" Type guard
def is_phase_list(value) -> bool:
return isinstance(value, list) and all(isinstance(p, dict) for p in value) Try / catch
try:
phases = seed_phases(task_kind)
except ValueError as e:
logger.error("todo_phases.toml malformed for %s: %s", task_kind, e)
raise # or degrade to [] if the workflow tolerates no seeded phases Prevention
- Write phase lists with `[[todo_phases.<kind>]]` array-of-tables syntax so the type is unambiguous
- Remember a missing task_kind key is legal (returns []); wrong type is what raises — audit key spellings separately
- Validate todo_phases.toml (every value a list of tables with non-empty name/tasks) at service startup
- Add a regression test calling seed_phases for every task_kind used in the codebase
When it happens
Trigger: Calling `seed_phases('bug')`, `seed_phases('question')`, etc., when `todo_phases.toml` defines `bug = "reproduce then fix"`, `bug = 3`, or `[todo_phases.bug]` (a bare table) instead of an array of phase tables such as `bug = [{ name = ..., tasks = [...] }]` or `[[todo_phases.bug]]` blocks.
Common situations: A hand-edit or bad merge replacing the array with a scalar; a YAML/JSON-style paste where list brackets were lost; using `[todo_phases.bug]` table syntax (raises) instead of `[[todo_phases.bug]]` array-of-tables; seeing this error means the key exists — a typo'd task_kind would silently return [] instead.
Related errors
- {context} must be a table
- prompt data file {name!r} must contain a TOML table
- {context} must be a non-empty string
- OMP_AUTH_BROKER_ACCOUNT_POOL_FILE contains an empty provider
- OMP_AUTH_BROKER_ACCOUNT_POOL_FILE contains a provider id wit
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/5abe709ce68141fa.
Report an issue: GitHub.