can1357/oh-my-pi · error · ValueError
{context} must be a table
Error message
{context} must be a table What it means
`_require_mapping(value, context)` validates that a value loaded from a prompt TOML data file is a table (Mapping) and returns it; otherwise it raises ValueError with a context string naming the exact file, key, and index where the bad value lives. It guards nested structures such as each phase in `todo_phases.toml[<kind>][i]` and `host_tools.toml[<tool>].parameters`.
Source
Thrown at python/robomp/src/persona.py:62
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):
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(View on GitHub (pinned to 9690622007)
Solutions
- Read the context in the message — it names the exact file, key, and index of the value that is not a table
- Ensure the referenced key exists: add the missing `[<tool>]` section in `host_tools.toml`
- Convert the offending value into a TOML table: `[create_pr.parameters] issue_number = 'Issue number to reference'`
- Audit the whole file: `python -c "import tomllib; d=tomllib.load(open('host_tools.toml','rb')); print({k: type(v).__name__ for k,v in d.items()})"`
Example fix
# before (host_tools.toml) [create_pr] description = "Create a PR" parameters = "no params" # after [create_pr] description = "Create a PR" [create_pr.parameters] issue_number = "Issue number to reference"
Defensive patterns
Strategy: type-guard
Validate before calling
import tomllib
tools = tomllib.load(open("host_tools.toml", "rb"))
for name, entry in tools.items():
assert isinstance(entry, dict), f"{name} entry must be a table"
assert isinstance(entry.get("parameters", {}), dict), f"{name}.parameters must be a table" Type guard
def is_mapping(value) -> bool:
return isinstance(value, Mapping) Try / catch
try:
desc = host_tool_parameter_description(tool, param)
except ValueError as e:
logger.error("host_tools.toml structure invalid: %s", e)
raise # config errors should be surfaced, not defaulted Prevention
- Keep every tool entry as `[tool_name]` with a `[tool_name.parameters]` sub-table
- Validate host_tools.toml at startup with a schema check over all entries
- Wrap any non-table value with a table header rather than using a string/inline value
- Keep TOML and Python tool definitions in sync — test that every registered tool has a TOML entry
When it happens
Trigger: Calling `seed_phases(task_kind)` where a phase entry is a scalar/string instead of a `[phase]` table; `_host_tool_entry(tool_name)` (via `host_tool_description`/`host_tool_parameter_description`) when the tool key is missing from `host_tools.toml` (`.get()` returns None) or defined as a non-table; `classify_next_step` reading a malformed tool/parameter entry.
Common situations: Misspelled tool name in `host_tools.toml` so the key lookup returns None; writing `parameters = "none"` as a string instead of a `[<tool>.parameters]` table; a phase in `todo_phases.toml` written as a bare string inside the list; a TOML typo turning a section into a value (`parameters = true`).
Related errors
- todo_phases.toml[{task_kind!r}] must be a list of phases
- 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/077f3235c5c4439e.
Report an issue: GitHub.