tirth8205/code-review-graph · error · TypeError
Unsupported TOML value: {type(value)!r}
Error message
Unsupported TOML value: {type(value)!r} What it means
_format_toml_value() serializes strings, bools, and (recursively) lists of those; any other type — int, float, dict, None, datetime — hits the final TypeError. It exists to keep generated TOML (e.g. merged MCP server blocks) strictly within the supported subset.
Source
Thrown at code_review_graph/skills.py:433
servers = parsed.get("mcpServers")
if isinstance(servers, dict) and "code-review-graph" in servers:
print(
f" OpenCode: legacy config found at {legacy}; leaving it unchanged. "
"OpenCode now reads opencode.json or opencode.jsonc with a top-level "
"'mcp' setting."
)
def _format_toml_value(value: Any) -> str:
"""Format a primitive Python value as TOML."""
if isinstance(value, str):
escaped = value.replace("\\", "\\\\").replace('"', '\\"')
return f'"{escaped}"'
if isinstance(value, bool):
return "true" if value else "false"
if isinstance(value, list):
return "[" + ", ".join(_format_toml_value(item) for item in value) + "]"
raise TypeError(f"Unsupported TOML value: {type(value)!r}")
def _merge_toml_mcp_server(
config_path: Path,
server_name: str,
server_entry: dict[str, Any],
dry_run: bool = False,
) -> bool:
"""Append a Codex MCP server section without clobbering the rest of the file."""
section_header = f"[mcp_servers.{server_name}]"
existing = ""
if config_path.exists():
existing = config_path.read_text(encoding="utf-8")
if section_header in existing:
return False
section_lines = [section_header]
for key, value in server_entry.items():View on GitHub (pinned to b58668751a)
Solutions
- Convert numeric values to strings before merging (str(port)) — quickest fix at the call site.
- Strip None values from the dict (or map them to empty strings) before passing it in.
- If you control the library, extend _format_toml_value with int/float branches: return str(value).
Example fix
# before
server_entry = {"command": "uvx", "args": ["crg"], "port": 8080}
_merge_toml_mcp_server(path, "crg", server_entry)
# after
server_entry = {"command": "uvx", "args": ["crg"], "port": "8080"}
_merge_toml_mcp_server(path, "crg", server_entry) Defensive patterns
Strategy: type-guard
Validate before calling
def coerce_toml_scalars(value):
if isinstance(value, (int, float)) and not isinstance(value, bool):
return str(value)
if value is None:
return ""
if isinstance(value, dict):
return {k: coerce_toml_scalars(v) for k, v in value.items()}
if isinstance(value, list):
return [coerce_toml_scalars(v) for v in value]
return value
server_entry = coerce_toml_scalars(server_entry) Type guard
def is_toml_formattable(value) -> bool:
if isinstance(value, bool) or isinstance(value, str):
return True
if isinstance(value, list):
return all(is_toml_formattable(v) for v in value)
return False Try / catch
try:
_merge_toml_mcp_server(config_path, name, server_entry)
except TypeError as exc:
if "Unsupported TOML value" in str(exc):
server_entry = {k: str(v) if isinstance(v, (int, float)) else v for k, v in server_entry.items()}
_merge_toml_mcp_server(config_path, name, server_entry) Prevention
- Keep MCP server config values as strings/bools only; stringify ports and numbers.
- Reject or strip None values before merging config into TOML.
- Add a test asserting every value in generated server entries passes the formatter.
When it happens
Trigger: Passing a config dict to _merge_toml_mcp_server whose values include numbers, nulls, nested tables (dicts), or any non-str/bool/list type — for example command port: 8080 or an env entry with a null value.
Common situations: Hand-written config dicts using JSON/YAML idioms (ints for ports, nulls for optional keys); data loaded from JSON with numeric scalars; newer config schemas adding typed values the formatter was never taught.
Related errors
AI-assisted analysis of tirth8205/code-review-graph@b58668751a (2026-08-28).
Data as JSON: /api/errors/fb9f4c7465f133f9.
Report an issue: GitHub.