can1357/oh-my-pi · error · ValueError
prompt data file {name!r} must contain a TOML table
Error message
prompt data file {name!r} must contain a TOML table What it means
`_load_toml(name)` reads a package-data file from `robomp.prompts`, parses it with `tomllib`, and requires the parsed document to be a TOML table (Mapping). If the top-level document parses to a non-table — a bare string, array, or number, all valid TOML — a ValueError is raised, because every caller indexes into the result with `.get()`.
Source
Thrown at python/robomp/src/persona.py:56
if isinstance(value, (list, tuple)):
return ", ".join(str(item) for item in value)
return str(value)
def render(template: str, scope: Mapping[str, Any]) -> str:
return _PLACEHOLDER.sub(lambda m: _lookup(m.group(1), scope), template)
@cache
def _load(name: str) -> str:
return resources.files("robomp.prompts").joinpath(name).read_text(encoding="utf-8")
@cache
def _load_toml(name: str) -> Mapping[str, Any]:
data = tomllib.loads(_load(name))
if not isinstance(data, Mapping):
raise ValueError(f"prompt data file {name!r} must contain a TOML table")
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):View on GitHub (pinned to 9690622007)
Solutions
- Open the offending .toml in `python/robomp/src/prompts/` and ensure the top level is a table: wrap content under explicit headers like `[todo_phases.bug]` or `[create_pr]`
- Restore a clobbered file with `git checkout -- python/robomp/src/prompts/<name>.toml` if a merge broke it
- Validate: `python -c "import tomllib; print(type(tomllib.load(open('<path>','rb'))))"` must print `<class 'dict'>`
- Restart the process after fixing — `_load_toml` is `@cache`d, so edits are not picked up mid-process
Example fix
# before (todo_phases.toml)
[[phase]]
name = "reproduce"
# after
[todo_phases]
bug = [{ name = "reproduce", tasks = ["write repro", "confirm failure"] }] Defensive patterns
Strategy: validation
Validate before calling
import tomllib
data = tomllib.load(open("python/robomp/src/prompts/todo_phases.toml", "rb"))
assert isinstance(data, dict), "TOML top level must be a table" Type guard
def is_table(value) -> bool:
import collections.abc
return isinstance(value, collections.abc.Mapping) Try / catch
try:
phases = seed_phases(task_kind)
except ValueError as e:
logger.error("prompt data TOML malformed: %s", e)
raise # fail fast at startup; prompt data errors should not be swallowed Prevention
- Always start prompt data .toml files with an explicit top-level table header
- Run a startup-time validation that parses every file in robomp/prompts/ and asserts a dict top level
- Fail fast at service startup by calling seed_phases/host_tool_description once during init
- Restart the process after editing TOML files — they are cached with @cache
When it happens
Trigger: Calling `seed_phases(task_kind)` or `_host_tool_entry(tool_name)` (indirectly `host_tool_description`, `host_tool_parameter_description`, `classify_next_step`) when `todo_phases.toml` or `host_tools.toml` in `python/robomp/src/prompts/` starts with a bare TOML value or contains only array-of-tables (`[[...]]`) with no top-level table header, so `tomllib.loads` returns a list instead of a dict.
Common situations: Editing a prompt data file and deleting the `[todo_phases.<kind>]` / `[<tool>]` table headers; a bad merge leaving the file as a bare array; reformatting the file with a tool that emits a top-level array; shipping a file whose first non-comment line is a lone literal.
Related errors
- {context} must be a table
- {context} must be a non-empty string
- todo_phases.toml[{task_kind!r}] must be a list of phases
- 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/e9aa752b213a2377.
Report an issue: GitHub.