rohitg00/ai-engineering-from-scratch · error · ValueError

name must be a string

Error message

name must be a string

What it means

For prompts/get, the server does params["name"] and requires a str. Like error 106's URI check, a missing name key raises KeyError, so this message specifically means name is present but not a string — an int, dict, None, or list. The type check runs before the registry lookup, so a string name with no matching prompt gives error 109 instead.

Source

Thrown at certifications/claude/lessons/11-mcp-server-design-and-integration/code/main.py:293

                        "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)
            ]
            return self._complete(
                prompts=prompts, ttlMs=300_000, cacheScope="public"
            ), []
        if method == "prompts/get":
            name = params["name"]
            if not isinstance(name, str):
                raise ValueError("name must be a string")
            if name not in self.prompts:
                raise ValueError("unknown prompt")
            return self._complete(
                messages=[
                    {
                        "role": "user",
                        "content": {"type": "text", "text": self.prompts[name]},
                    }
                ]
            ), []
        raise LookupError(f"Method not found: {method}")

    def _call_tool(
        self, params: dict[str, Any], metadata: dict[str, Any]
    ) -> tuple[dict[str, Any], list[dict[str, Any]]]:
        name = params["name"]
        if not isinstance(name, str) or not name:
            raise ValueError("name must be a non-empty string")

View on GitHub (pinned to 39ea8a1c6d)

Solutions

  1. Pass the prompt name as a string, e.g. "code-review"
  2. If the name comes from structured data, extract and stringify it first (str(prompt["name"]))
  3. Guard with isinstance(name, str) before the exchange call

Example fix

# before
server.exchange("prompts/get", {"name": {"id": "code-review"}, "_meta": meta})
# after
server.exchange("prompts/get", {"name": "code-review", "_meta": meta})
Defensive patterns

Strategy: type-guard

Validate before calling

name = payload.get("name")
if not isinstance(name, str):
    raise TypeError("prompt name must be a string")
payload["name"] = name

Type guard

def is_valid_prompt_name(params: dict) -> bool:
    return isinstance(params.get("name"), str)

Prevention

When it happens

Trigger: prompts/get with name set to 123, ["summary"], {"id": "summary"}, or None; passing a prompt object instead of its name field.

Common situations: Loading prompt identifiers from typed configs where they deserialize as non-strings; refactors that changed name from str to an enum/object without updating call sites; None defaults leaking into requests.

Related errors


AI-assisted analysis of rohitg00/ai-engineering-from-scratch@39ea8a1c6d (2026-08-26). Data as JSON: /api/errors/fa45e80675f13cb5. Report an issue: GitHub.