{"record":{"id":"3259d0a0edd33824","repo":"unslothai/unsloth","slug":"known-block-type-handled-by-its-typed-model","errorCode":null,"errorMessage":"known block type handled by its typed model","messagePattern":"known block type handled by its typed model","errorType":"validation","errorClass":"ValueError","httpStatus":422,"severity":"info","filePath":"studio/backend/models/inference.py","lineNumber":2456,"sourceCode":"\n# Block types the converter translates explicitly. Anything else (thinking /\n# redacted_thinking, a provider block a resumed session replays, or a future type)\n# is accepted as an unknown block and dropped by the converter, rather than 400-ing\n# the whole request on strict validation.\n_KNOWN_ANTHROPIC_BLOCK_TYPES = frozenset({\"text\", \"image\", \"tool_use\", \"tool_result\"})\n\n\nclass AnthropicUnknownBlock(BaseModel):\n    type: str\n    model_config = {\"extra\": \"allow\"}\n\n    @field_validator(\"type\")\n    @classmethod\n    def _only_unknown_types(cls, v):\n        # Known types parse as their typed models above (so a malformed known block\n        # still fails cleanly); this fallback only catches the rest.\n        if v in _KNOWN_ANTHROPIC_BLOCK_TYPES:\n            raise ValueError(\"known block type handled by its typed model\")\n        return v\n\n\nAnthropicContentBlock = Union[\n    AnthropicTextBlock,\n    AnthropicImageBlock,\n    AnthropicToolUseBlock,\n    AnthropicToolResultBlock,\n    AnthropicUnknownBlock,\n]\n\n\ndef _anthropic_content_to_system_text(content: Any) -> str:\n    \"\"\"Convert misplaced system message content into Anthropic system text.\"\"\"\n    if content is None:  # null content must not become the literal \"None\"\n        return \"\"\n    if isinstance(content, str):\n        return content","sourceCodeStart":2438,"sourceCodeEnd":2474,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/models/inference.py#L2438-L2474","documentation":"Internal sentinel raised by AnthropicUnknownBlock's type validator when a block whose type is in _KNOWN_ANTHROPIC_BLOCK_TYPES reaches the fallback model. The Union is ordered so known types (text/image/tool_use/tool_result) parse as their typed models first; only genuinely unknown types should land here. Seeing this message means the discriminators did not route a known block to its typed model — effectively an internal invariant, not a client error.","triggerScenarios":"A content block with type 'text'/'image'/etc. that is malformed enough to fail its typed model's parsing (so Pydantic tries the fallback) — for example a text block missing required fields. Under Pydantic smart union the fallback then also rejects it, collapsing to a clean validation error rather than a silent passthrough.","commonSituations":"Gateway/proxy tests that construct half-valid Anthropic blocks; upstream schema drift adding a required field to a known block model so previously valid blocks no longer match the typed model; fuzzing the messages endpoint with mutated block payloads.","solutions":["Inspect the failing block JSON and fix the malformed known-type block (missing/incorrect fields).","If you maintain the server, check that the typed block models still accept legitimate payloads after an upgrade.","Do not attempt to send known-type blocks through the 'unknown block' escape hatch — the validator forbids it by design."],"exampleFix":"// before\n{\"type\": \"text\", \"text\": null}  // null text fails AnthropicTextBlock, falls through\n\n// after\n{\"type\": \"text\", \"text\": \"hello\"}","handlingStrategy":"try-catch","validationCode":"KNOWN = {'text', 'image', 'tool_use', 'tool_result'}\ndef block_parses_as_known(block: dict) -> bool:\n    # best-effort client mirror; full checking belongs to the server models\n    return block.get('type') in KNOWN","typeGuard":"def is_unknown_block(block: dict) -> bool:\n    return isinstance(block.get('type'), str) and block['type'] not in {\n        'text', 'image', 'tool_use', 'tool_result'\n    }","tryCatchPattern":"try:\n    req = AnthropicMessagesRequest.model_validate_json(body)\nexcept ValidationError:\n    # inspect which block failed; fix the malformed known-type block\n    log_and_return_400()\n","preventionTips":["Treat this message as an internal invariant: the block payload is malformed for its declared known type","Keep typed block models in lockstep with upstream schema changes","Fuzz-test block endpoints with mutated payloads to catch drift early"],"tags":["pydantic","validation","anthropic","content-blocks","internal-invariant"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}