rohitg00/ai-engineering-from-scratch · error · ValueError
Messages API response must be an object
Error message
Messages API response must be an object
What it means
Raised in AnthropicMessagesHTTPTransport.create_message when the HTTP 200 response body decodes to something other than a JSON object. The Messages API contract requires a top-level object (content, stop_reason, usage), so a list, string, or scalar body means the response is not a valid Messages reply.
Solutions
- Confirm the endpoint actually serves the Messages API and is not returning a JSON array or plain text
- Check for intercepting proxies or gateways that rewrap responses
- Assert the response shape in tests with a fake transport returning a well-formed message object
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at certifications/claude/lessons/30-developer-application-capstone/code/main.py:68 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of rohitg00/ai-engineering-from-scratch@39ea8a1c6d (2026-08-26).
Data as JSON: /api/errors/b9f8ecd78b98d71d.
Report an issue: GitHub.
Appendix: source
Thrown at certifications/claude/lessons/30-developer-application-capstone/code/main.py:68
def create_message(self, payload: dict[str, Any]) -> dict[str, Any]:
body = json.dumps(payload).encode("utf-8")
request = urllib.request.Request(
self.endpoint,
data=body,
method="POST",
headers={
"content-type": "application/json",
"anthropic-version": ANTHROPIC_VERSION,
"x-api-key": self._api_key,
},
)
try:
with self._opener(request, timeout=self.timeout_seconds) as response:
decoded = json.loads(response.read().decode("utf-8"))
except urllib.error.HTTPError as error:
raise RuntimeError(f"Messages API returned HTTP {error.code}") from None
if not isinstance(decoded, dict):
raise ValueError("Messages API response must be an object")
return decoded
def build_live_order_request(request: str, model: str) -> dict[str, Any]:
"""Build an inspectable wire payload with the same bounded lookup contract."""
return {
"model": model,
"max_tokens": 128,
"system": (
"You are a bounded order-status router. Use lookup_order only when "
"the user supplies an exact public order ID. Never claim execution."
),
"messages": [{"role": "user", "content": request}],
"tools": [
{
"name": "lookup_order",
"description": "Read one visible order status. Never changes order state.",
"input_schema": {View on GitHub (pinned to 39ea8a1c6d)