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
- Upgrade the server so set_host_tools echoes toolNames
- Check server logs for why the registration failed (schema-invalid tool definitions)
- Align client/server versions; the field comes from a specific protocol revision
- 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
- Match server version to the client protocol revision that introduced toolNames
- Ensure tool specs conform to the expected schema before registration
- Make test doubles echo {"toolNames": [...]}
- Check server logs for registration rejections
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
- set_model returned an empty payload
- get_messages_page response has an invalid totalMessages
- get_messages_page response has an invalid nextCursor
- set_host_uri_schemes response did not include schemes
- RPC response payload must be an object
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/7821336780d2caae.
Report an issue: GitHub.