{"record":{"id":"94309f3e4ccf80fc","repo":"rohitg00/ai-engineering-from-scratch","slug":"inputresponses-entries-must-be-objects","errorCode":null,"errorMessage":"inputResponses entries must be objects","messagePattern":"inputResponses entries must be objects","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"certifications/claude/lessons/11-mcp-server-design-and-integration/code/main.py","lineNumber":412,"sourceCode":"        self.state_signer.verify(state, \"tools/call\", \"prepare_review\", arguments)\n        if not isinstance(responses, dict):\n            return self._input_required(inputRequests=input_requests, requestState=state)\n        missing_responses = {\n            key: request for key, request in input_requests.items() if key not in responses\n        }\n        if missing_responses:\n            return self._input_required(\n                inputRequests=missing_responses, requestState=state\n            )\n\n        workspace_scope = responses[\"workspace_scope\"]\n        review_sample = responses[\"review_sample\"]\n        elicitation = responses[\"review_goal\"]\n        if not all(\n            isinstance(response, dict)\n            for response in (workspace_scope, review_sample, elicitation)\n        ):\n            raise ValueError(\"inputResponses entries must be objects\")\n        elicitation_content = elicitation.get(\"content\", {})\n        if not isinstance(elicitation_content, dict):\n            raise ValueError(\"review_goal.content must be an object\")\n        roots = workspace_scope.get(\"roots\")\n        sample_content = review_sample.get(\"content\", {})\n        goal = elicitation_content.get(\"goal\")\n        if not isinstance(roots, list) or not isinstance(sample_content, dict):\n            raise ValueError(\"inputResponses contain invalid roots or sampling results\")\n        if elicitation.get(\"action\") != \"accept\" or not isinstance(goal, str):\n            raise ValueError(\"review_goal must be accepted with a string goal\")\n        sample = sample_content.get(\"text\")\n        if not isinstance(sample, str):\n            raise ValueError(\"review_sample must contain text\")\n        summary = {\n            \"goal\": goal,\n            \"rootCount\": len(roots),\n            \"sample\": sample,\n            \"topic\": arguments[\"topic\"],","sourceCodeStart":394,"sourceCodeEnd":430,"githubUrl":"https://github.com/rohitg00/ai-engineering-from-scratch/blob/39ea8a1c6d0b61f071226eff7ede4d4105fed820/certifications/claude/lessons/11-mcp-server-design-and-integration/code/main.py#L394-L430","documentation":"On the second round of prepare_review the server unpacks inputResponses['workspace_scope'], ['review_sample'], and ['review_goal']. Each must be a JSON object; any string, number, list, or null entry raises this before any field extraction happens.","triggerScenarios":"Resuming tools/call with requestState plus inputResponses like {\"workspace_scope\": \"file:///repo\", \"review_sample\": [...], \"review_goal\": null}.","commonSituations":"Client stores the raw roots URI string instead of a roots/list response object; partial serialization drops a response to null; replaying hand-written fixtures that do not match MCP response shapes.","solutions":["Wrap each entry as an object: a roots/list result for workspace_scope, a createMessage result for review_sample, an elicitation result for review_goal","Validate the inputResponses shape before resuming the call","Derive responses from the server's inputRequests descriptors rather than hand-writing them"],"exampleFix":"# before\nresponses = {\"workspace_scope\": \"file:///repo\"}\n\n# after\nresponses = {\"workspace_scope\": {\"roots\": []}}","handlingStrategy":"validation","validationCode":"for key in (\"workspace_scope\", \"review_sample\", \"review_goal\"):\n    entry = responses.get(key)\n    if not isinstance(entry, dict):\n        raise ValueError(f\"inputResponses[{key!r}] must be an object\")\nserver.exchange(\"tools/call\", {\"requestState\": state, \"inputResponses\": responses}, metadata=meta)","typeGuard":"def are_object_responses(responses: object) -> bool:\n    return isinstance(responses, dict) and all(\n        isinstance(responses.get(k), dict)\n        for k in (\"workspace_scope\", \"review_sample\", \"review_goal\")\n    )","tryCatchPattern":null,"preventionTips":["Build each response by executing the corresponding inputRequest, not by hand","Never substitute a URI string or list for a response object","Validate the whole inputResponses map before resuming the call"],"tags":["mcp","validation","elicitation","input-responses"],"backgroundTag":"schema-validation-failed","analyzedSha":"39ea8a1c6d0b61f071226eff7ede4d4105fed820","analyzedAt":"2026-08-26T03:13:46.626Z","schemaVersion":2},"datasetVersion":"2026-08-26T07:17:17.940Z"}