can1357/oh-my-pi · error · RpcError

set_host_tools response did not include toolNames

Error message

set_host_tools response did not include toolNames

What it means

set_host_tools() registers the host's custom tools with the server and expects the response to echo the accepted tool names in a 'toolNames' list. If payload.get('toolNames') (or an empty-list fallback) is not a list, the client raises this RpcError, since callers rely on the returned tuple of registered tool names.

Source

Thrown at python/omp-rpc/src/omp_rpc/client.py:1109

        payload = self._request(
            "set_host_tools",
            tools=cast(
                JsonValue,
                [
                    {
                        "name": tool.name,
                        "label": tool.label,
                        "description": tool.description,
                        "parameters": tool.parameters,
                        "hidden": tool.hidden,
                    }
                    for tool in self._custom_tools
                ],
            ),
        )
        tool_names = payload.get("toolNames") or []
        if not isinstance(tool_names, list):
            raise RpcError("set_host_tools response did not include toolNames")
        return tuple(str(name) for name in tool_names)

    def set_host_uris(self, host_uris: Sequence[HostUri[Any]]) -> tuple[str, ...]:
        self._host_uris = tuple(host_uris)
        if self._process is None:
            return tuple(uri.scheme for uri in self._host_uris)

        schemes_payload: list[JsonObject] = []
        for uri in self._host_uris:
            entry: JsonObject = {
                "scheme": uri.scheme,
                "writable": uri.writable,
                "immutable": uri.immutable,
            }
            if uri.description is not None:
                entry["description"] = uri.description
            schemes_payload.append(entry)

View on GitHub (pinned to 9690622007)

Solutions

  1. Upgrade the server so set_host_tools echoes toolNames
  2. Check server logs for why the registration failed (schema-invalid tool definitions)
  3. Align client/server versions; the field comes from a specific protocol revision
  4. In tests, make the stub return {"toolNames": [...]} matching the requested names

Example fix

# before: stub acks without the field
return {"ok": True}

# after
return {"toolNames": [t["name"] for t in received_tools]}
Defensive patterns

Strategy: try-catch

Validate before calling

# register only serializable, well-formed tool specs
specs = [{"name": t.name, "description": t.description} for t in tools]
assert all(isinstance(s["name"], str) and s["name"] for s in specs)

Type guard

def has_tool_names(payload: object) -> bool:
    names = (payload or {}).get("toolNames") if isinstance(payload, dict) else None
    return isinstance(names, list)

Try / catch

try:
    names = client.set_host_tools(tools)
except RpcError as e:
    if "did not include toolNames" in str(e):
        names = ()  # server too old or rejected registration; log and continue
    else:
        raise

Prevention

When it happens

Trigger: Server responds to set_host_tools without a toolNames array — older server builds predating the field, servers that reject/ignore custom tool registration, or stub servers returning a bare ack ({} or {"ok": true}).

Common situations: Client newer than the server (field added in a later protocol revision); custom tool definitions rejected server-side causing an error-shaped payload; mock servers that don't implement set_host_tools.

Related errors


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