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

  1. Convert numeric values to strings before merging (str(port)) — quickest fix at the call site.
  2. Strip None values from the dict (or map them to empty strings) before passing it in.
  3. 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

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.