{"record":{"id":"fb3fc5e2a73b6252","repo":"rohitg00/ai-engineering-from-scratch","slug":"review-sample-must-contain-text","errorCode":null,"errorMessage":"review_sample must contain text","messagePattern":"review_sample must contain text","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"certifications/claude/lessons/11-mcp-server-design-and-integration/code/main.py","lineNumber":425,"sourceCode":"        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\"],\n        }\n        return self._complete(\n            content=[{\"type\": \"text\", \"text\": json.dumps(summary, sort_keys=True)}],\n            isError=False,\n        )\n\n    @staticmethod\n    def _progress(token: str | int, progress: int, total: int, message: str) -> dict[str, Any]:\n        return {\n            \"jsonrpc\": \"2.0\",\n            \"method\": \"notifications/progress\",\n            \"params\": {\n                \"progressToken\": token,","sourceCodeStart":407,"sourceCodeEnd":443,"githubUrl":"https://github.com/rohitg00/ai-engineering-from-scratch/blob/39ea8a1c6d0b61f071226eff7ede4d4105fed820/certifications/claude/lessons/11-mcp-server-design-and-integration/code/main.py#L407-L443","documentation":"The final content check: the sampling response's content object must carry a 'text' string. An image/audio content object, a content dict without 'text', or text of the wrong type fails here after every earlier check has passed.","triggerScenarios":"review_sample content like {\"type\": \"image\", ...} or {\"content\": {}} — any createMessage result whose content lacks a string 'text' field.","commonSituations":"A model or sampling stub returns multimodal content; a client normalizes text away; an empty sampling result forwarded unchanged.","solutions":["Return text content: {\"content\": {\"type\": \"text\", \"text\": \"...\"}}","When sampling can yield images, request or force text-only output for this tool","Fail fast on missing text rather than sending an incomplete response"],"exampleFix":"# before\nreview_sample = {\"content\": {\"type\": \"image\", \"data\": \"...\"}}\n\n# after\nreview_sample = {\"content\": {\"type\": \"text\", \"text\": \"review focus: auth errors\"}}","handlingStrategy":"validation","validationCode":"text = responses[\"review_sample\"].get(\"content\", {}).get(\"text\")\nif not isinstance(text, str):\n    raise ValueError(\"sampling response must contain text content\")","typeGuard":"def has_text_content(sample: object) -> bool:\n    return (\n        isinstance(sample, dict)\n        and isinstance(sample.get(\"content\"), dict)\n        and isinstance(sample[\"content\"].get(\"text\"), str)\n    )","tryCatchPattern":null,"preventionTips":["Force text-only sampling output for tools that require text","Validate sampling results before forwarding them","Reject or convert multimodal content instead of forwarding it raw"],"tags":["mcp","sampling","validation","content"],"backgroundTag":"sampling-response-invalid","analyzedSha":"39ea8a1c6d0b61f071226eff7ede4d4105fed820","analyzedAt":"2026-08-26T03:13:46.626Z","schemaVersion":2},"datasetVersion":"2026-08-26T07:17:17.940Z"}