{"record":{"id":"c7b1beb43e1b5c4d","repo":"can1357/oh-my-pi","slug":"context-must-be-a-non-empty-string","errorCode":null,"errorMessage":"{context} must be a non-empty string","messagePattern":"(.+?) must be a non-empty string","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/robomp/src/persona.py","lineNumber":68,"sourceCode":"\n\n@cache\ndef _load_toml(name: str) -> Mapping[str, Any]:\n    data = tomllib.loads(_load(name))\n    if not isinstance(data, Mapping):\n        raise ValueError(f\"prompt data file {name!r} must contain a TOML table\")\n    return data\n\n\ndef _require_mapping(value: Any, context: str) -> Mapping[str, Any]:\n    if not isinstance(value, Mapping):\n        raise ValueError(f\"{context} must be a table\")\n    return value\n\n\ndef _require_nonempty_str(value: Any, context: str) -> str:\n    if not isinstance(value, str) or not value.strip():\n        raise ValueError(f\"{context} must be a non-empty string\")\n    return value\n\n\ndef seed_phases(task_kind: str) -> list[dict[str, Any]]:\n    raw_phases = _load_toml(\"todo_phases.toml\").get(task_kind, [])\n    if not isinstance(raw_phases, list):\n        raise ValueError(f\"todo_phases.toml[{task_kind!r}] must be a list of phases\")\n\n    phases: list[dict[str, Any]] = []\n    for phase_index, raw_phase in enumerate(raw_phases):\n        phase = _require_mapping(raw_phase, f\"todo_phases.toml[{task_kind!r}][{phase_index}]\")\n        name = _require_nonempty_str(\n            phase.get(\"name\"),\n            f\"todo_phases.toml[{task_kind!r}][{phase_index}].name\",\n        )\n        raw_tasks = phase.get(\"tasks\")\n        if not isinstance(raw_tasks, list) or not raw_tasks:\n            raise ValueError(f\"todo_phases.toml[{task_kind!r}][{phase_index}].tasks must be a non-empty list\")","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/robomp/src/persona.py#L50-L86","documentation":"`_require_nonempty_str(value, context)` validates that a value from a prompt TOML data file is a string with non-whitespace content and returns it; otherwise it raises ValueError naming the exact location. It guards `host_tools.toml[<tool>].description`, `host_tools.toml[<tool>].parameters[<name>]`, and phase `name`/`tasks` strings in `todo_phases.toml`.","triggerScenarios":"Calling `host_tool_description(tool)` when `host_tools.toml` lacks a `description` for that tool or sets it to a non-string/empty; `host_tool_parameter_description(tool, param)` when `[tool.parameters]` lacks the parameter key or its value is empty/whitespace; `seed_phases(kind)` when a phase's `name` or an entry of its `tasks` list is missing (None), empty (\"\"), whitespace (\" \"), or a non-string like an integer.","commonSituations":"Adding a new host tool to `host_tools.toml` and forgetting the `description` field or a parameter description; renaming a parameter in Python without updating the TOML so the key lookup returns None; an editor stripping content leaving `name = \"\"`; quoting mistakes turning a description into a TOML boolean or array.","solutions":["Read the context in the message to locate the exact `[<tool>]`, `parameters[<name>]`, or `todo_phases[<kind>][i].name/tasks[j]` that is empty/absent","Fill in a meaningful non-empty string at that location, or restore the file with `git checkout -- python/robomp/src/prompts/<file>.toml`","Keep parameter names in `host_tools.toml` in sync with the Python tool definitions after renames","Quickly audit: `python -c \"import tomllib; d=tomllib.load(open('host_tools.toml','rb')); [print(k, bool(d[k].get('description','').strip())) for k in d]\"`"],"exampleFix":"# before (host_tools.toml)\n[triage_issue]\ndescription = \"\"\n\n# after\n[triage_issue]\ndescription = \"Apply triage labels to the issue\"","handlingStrategy":"validation","validationCode":"import tomllib\ntools = tomllib.load(open(\"host_tools.toml\", \"rb\"))\nfor name, entry in tools.items():\n    d = entry.get(\"description\")\n    assert isinstance(d, str) and d.strip(), f\"{name}.description missing/empty\"\n    for p, pd in entry.get(\"parameters\", {}).items():\n        assert isinstance(pd, str) and pd.strip(), f\"{name}.parameters[{p}] missing/empty\"","typeGuard":"def is_nonempty_str(value) -> bool:\n    return isinstance(value, str) and bool(value.strip())","tryCatchPattern":"try:\n    desc = host_tool_description(tool_name)\nexcept ValueError as e:\n    logger.error(\"host_tools.toml field missing: %s\", e)\n    raise  # misconfiguration must be surfaced, not silently defaulted","preventionTips":["Add a startup pass asserting every tool has a non-empty description and every parameter a non-empty description","Unit-test that host_tools.toml keys match the registered host tools to catch renames/drift","Avoid empty or whitespace placeholder strings when drafting entries","Re-validate prompt data files after merges before deploying"],"tags":["toml","configuration","validation","empty-string"],"backgroundTag":"toml-schema-validation-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}