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

  1. 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]`
  2. Restore a clobbered file with `git checkout -- python/robomp/src/prompts/<name>.toml` if a merge broke it
  3. Validate: `python -c "import tomllib; print(type(tomllib.load(open('<path>','rb'))))"` must print `<class 'dict'>`
  4. 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

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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/e9aa752b213a2377. Report an issue: GitHub.