{"record":{"id":"fc2021a0a531f5c7","repo":"oobabooga/textgen","slug":"messages-unsupported-content-type","errorCode":null,"errorMessage":"messages: unsupported content type","messagePattern":"messages: unsupported content type","errorType":"exception","errorClass":"InvalidRequestError","httpStatus":400,"severity":"error","filePath":"modules/api/completions.py","lineNumber":517,"sourceCode":"        elif m['role'] == 'function':\n            raise InvalidRequestError(message=\"role: function is not supported.\", param='messages')\n\n        # Handle multimodal content validation\n        content = m.get('content')\n        if content is None:\n            # OpenAI allows content: null on assistant messages when tool_calls is present\n            if m['role'] == 'assistant' and m.get('tool_calls'):\n                m['content'] = ''\n            else:\n                raise InvalidRequestError(message=\"messages: missing content\", param='messages')\n\n        # Validate multimodal content structure\n        if isinstance(content, list):\n            for item in content:\n                if not isinstance(item, dict) or 'type' not in item:\n                    raise InvalidRequestError(message=\"messages: invalid content item format\", param='messages')\n                if item['type'] not in ['text', 'image_url']:\n                    raise InvalidRequestError(message=\"messages: unsupported content type\", param='messages')\n                if item['type'] == 'text' and 'text' not in item:\n                    raise InvalidRequestError(message=\"messages: missing text in content item\", param='messages')\n                if item['type'] == 'image_url' and ('image_url' not in item or 'url' not in item['image_url']):\n                    raise InvalidRequestError(message=\"messages: missing image_url in content item\", param='messages')\n\n    # Chat Completions\n    object_type = 'chat.completion' if not stream else 'chat.completion.chunk'\n    created_time = int(time.time())\n    cmpl_id = \"chatcmpl-%d\" % (int(time.time() * 1000000000))\n    resp_list = 'data' if is_legacy else 'choices'\n\n    # generation parameters\n    generate_params = process_parameters(body, is_legacy=is_legacy)\n    if stop_event is not None:\n        generate_params['stop_event'] = stop_event\n    continue_ = body['continue_']\n\n    # Instruction template","sourceCodeStart":499,"sourceCodeEnd":535,"githubUrl":"https://github.com/oobabooga/textgen/blob/ed888c71f221df552750e1834b3654abab8ae345/modules/api/completions.py#L499-L535","documentation":"In multimodal content lists, only item types 'text' and 'image_url' are accepted. Any other 'type' value (e.g. 'image', 'audio', 'input_audio', 'video') raises InvalidRequestError (400, param='messages').","triggerScenarios":"POST /v1/chat/completions with a content item like {\"type\": \"image\", \"source\": ...} (Anthropic style), {\"type\": \"audio\", ...}, or {\"type\": \"refusal\"}.","commonSituations":"Porting Anthropic Messages API payloads ('type': 'image' with 'source') to this OpenAI-compatible server; using newer OpenAI audio content types this backend never implemented; typos like 'imageURL'.","solutions":["Convert to OpenAI vision format: {\"type\": \"image_url\", \"image_url\": {\"url\": <url or data: URI>}}.","Strip unsupported content types (audio/refusal/etc.) before sending.","Ensure a multimodal (llava/multimodal-projector) model is actually loaded if you want image inputs to work downstream."],"exampleFix":"# before\n{\"type\": \"image\", \"source\": {\"type\": \"base64\", \"media_type\": \"image/png\", \"data\": b64}}\n\n# after\n{\"type\": \"image_url\", \"image_url\": {\"url\": \"data:image/png;base64,\" + b64}}","handlingStrategy":"validation","validationCode":"ALLOWED = {'text', 'image_url'}\n\ndef strip_unsupported_types(content):\n    if isinstance(content, str):\n        return content\n    return [i for i in content if isinstance(i, dict) and i.get('type') in ALLOWED]","typeGuard":"def has_supported_types(content) -> bool:\n    return isinstance(content, str) or all(isinstance(i, dict) and i.get('type') in ('text', 'image_url') for i in content)","tryCatchPattern":"try:\n    resp = client.chat.completions.create(model=m, messages=msgs)\nexcept openai.BadRequestError as e:\n    if 'unsupported content type' in str(e):\n        msgs = [{'role': r['role'], 'content': strip_unsupported_types(r['content']) if isinstance(r.get('content'), list) else r.get('content')} for r in msgs]\n        resp = client.chat.completions.create(model=m, messages=msgs)\n    else:\n        raise","preventionTips":["Convert Anthropic-style {'type':'image','source':...} blocks to image_url before sending.","Drop audio/refusal items; this backend only understands text and image_url.","Centralize content-block conversion in one function instead of inline dicts."],"tags":["openai-api","chat-completions","multimodal","validation"],"backgroundTag":null,"analyzedSha":"ed888c71f221df552750e1834b3654abab8ae345","analyzedAt":"2026-08-15T05:24:21.000Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}