rohitg00/ai-engineering-from-scratch · error · ValueError
uri must be a string
Error message
uri must be a string
What it means
For resources/read, the server does params["uri"] and requires the value to be a str before consulting its resource table. A missing uri raises KeyError instead, so this specific message means uri exists but is the wrong type — number, dict, list, bool, or None. The check happens before the existence check, so a well-typed unknown URI gives error 107 instead.
Source
Thrown at certifications/claude/lessons/11-mcp-server-design-and-integration/code/main.py:268
for tool in sorted(self.tools.values(), key=lambda item: item.name)
]
return self._complete(
tools=tools, ttlMs=300_000, cacheScope="public"
), []
if method == "tools/call":
return self._call_tool(params, metadata)
if method == "resources/list":
resources = [
{"uri": uri, "name": uri.removeprefix("config://")}
for uri in sorted(self.resources)
]
return self._complete(
resources=resources, ttlMs=60_000, cacheScope="private"
), []
if method == "resources/read":
uri = params["uri"]
if not isinstance(uri, str):
raise ValueError("uri must be a string")
if uri not in self.resources:
raise ValueError("unknown resource")
return self._complete(
contents=[
{
"uri": uri,
"mimeType": "application/json",
"text": self.resources[uri],
}
],
ttlMs=30_000,
cacheScope="private",
), []
if method == "prompts/list":
prompts = [
{"name": name, "description": self.prompts[name]}
for name in sorted(self.prompts)
]View on GitHub (pinned to 39ea8a1c6d)
Solutions
- Pass the URI as a plain string: "study://catalog"
- If the URI comes from structured input, extract the string field first (uri["href"], str(uri))
- Validate with isinstance(uri, str) before calling exchange
Example fix
# before
server.exchange("resources/read", {"uri": {"scheme": "study", "path": "/catalog"}, "_meta": meta})
# after
server.exchange("resources/read", {"uri": "study://catalog", "_meta": meta}) Defensive patterns
Strategy: type-guard
Validate before calling
uri = payload.get("uri")
if not isinstance(uri, str):
raise TypeError("uri must be a string")
payload["uri"] = uri Type guard
def is_valid_uri_param(params: dict) -> bool:
return isinstance(params.get("uri"), str) Prevention
- Stringify URIs at the edge where they enter your client
- Prefer plain string URIs over structured URL objects in MCP payloads
- Validate uri type in the request builder shared by all resources/read calls
When it happens
Trigger: resources/read with uri set to 42, None, {"href": "..."}, or a URL object that was never stringified; JSON where the value is an array of URIs.
Common situations: Passing an identifier object instead of its string field; config-driven URIs loaded as non-strings; f-string templating bugs producing nested structures.
Related errors
AI-assisted analysis of rohitg00/ai-engineering-from-scratch@39ea8a1c6d (2026-08-26).
Data as JSON: /api/errors/07ca77df150b7948.
Report an issue: GitHub.