rohitg00/ai-engineering-from-scratch · error · ValueError
review_goal.content must be an object
Error message
review_goal.content must be an object
What it means
Inside the review_goal elicitation response, content must be an object because it carries the form fields — here the 'goal' string. A string or list content, even a plausible one like the goal text itself, is rejected before goal extraction.
Source
Thrown at certifications/claude/lessons/11-mcp-server-design-and-integration/code/main.py:415
missing_responses = {
key: request for key, request in input_requests.items() if key not in responses
}
if missing_responses:
return self._input_required(
inputRequests=missing_responses, requestState=state
)
workspace_scope = responses["workspace_scope"]
review_sample = responses["review_sample"]
elicitation = responses["review_goal"]
if not all(
isinstance(response, dict)
for response in (workspace_scope, review_sample, elicitation)
):
raise ValueError("inputResponses entries must be objects")
elicitation_content = elicitation.get("content", {})
if not isinstance(elicitation_content, dict):
raise ValueError("review_goal.content must be an object")
roots = workspace_scope.get("roots")
sample_content = review_sample.get("content", {})
goal = elicitation_content.get("goal")
if not isinstance(roots, list) or not isinstance(sample_content, dict):
raise ValueError("inputResponses contain invalid roots or sampling results")
if elicitation.get("action") != "accept" or not isinstance(goal, str):
raise ValueError("review_goal must be accepted with a string goal")
sample = sample_content.get("text")
if not isinstance(sample, str):
raise ValueError("review_sample must contain text")
summary = {
"goal": goal,
"rootCount": len(roots),
"sample": sample,
"topic": arguments["topic"],
}
return self._complete(
content=[{"type": "text", "text": json.dumps(summary, sort_keys=True)}],View on GitHub (pinned to 39ea8a1c6d)
Solutions
- Match the requestedSchema in the server's elicitation/create params — content is an object with a goal string field
- Wrap free-text goals: content = {"goal": value}"
- Log the elicitation request's requestedSchema before building the response
Example fix
# before
review_goal = {"action": "accept", "content": "check error handling"}
# after
review_goal = {"action": "accept", "content": {"goal": "check error handling"}} Defensive patterns
Strategy: validation
Validate before calling
content = elicitation_response.get("content")
if not isinstance(content, dict):
elicitation_response["content"] = content = {}
if not isinstance(content.get("goal"), str):
raise ValueError("elicitation content must be an object with a string goal") Type guard
def is_form_content(content: object) -> bool:
return isinstance(content, dict) and isinstance(content.get("goal"), str) Prevention
- Shape elicitation responses from the request's requestedSchema
- Keep form fields as object keys, never flattened strings
- Unit-test the response builder against the schema
When it happens
Trigger: Sending {"action": "accept", "content": "review the auth flow"} instead of {"action": "accept", "content": {"goal": "review the auth flow"}}.
Common situations: Elicitation form output flattened to a plain string by middleware; a client that models elicitation content like sampling text content; schema drift between the client form and the server's requestedSchema.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- inputResponses entries must be objects
- review_goal must be accepted with a string goal
- -32600
- -32603
- expected object
AI-assisted analysis of rohitg00/ai-engineering-from-scratch@39ea8a1c6d (2026-08-26).
Data as JSON: /api/errors/a691c97071e5e08d.
Report an issue: GitHub.