{"record":{"id":"27e4abc2c6d9a100","repo":"BerriAI/litellm","slug":"each-content-item-must-have-a-string-type-field","errorCode":null,"errorMessage":"Each content item must have a string `type` field","messagePattern":"Each content item must have a string `type` field","errorType":"validation","errorClass":"OCIError","httpStatus":400,"severity":"error","filePath":"litellm/llms/oci/chat/generic.py","lineNumber":76,"sourceCode":"\ndef adapt_messages_to_generic_oci_standard_content_message(role: str, content: str | list) -> OCIMessage:\n    \"\"\"Convert a plain-text or multipart content message to OCI format.\"\"\"\n    new_content: Final[list[OCIContentPartUnion]] = []\n    if isinstance(content, str):\n        return OCIMessage(\n            role=open_ai_to_generic_oci_role_map[role],\n            content=[OCITextContentPart(text=content)],\n            toolCalls=None,\n            toolCallId=None,\n        )\n\n    for content_item in content:\n        if not isinstance(content_item, dict):\n            raise OCIError(status_code=400, message=\"Each content item must be a dictionary\")\n\n        item_type = content_item.get(\"type\")\n        if not isinstance(item_type, str):\n            raise OCIError(\n                status_code=400,\n                message=\"Each content item must have a string `type` field\",\n            )\n        if item_type not in [\"text\", \"image_url\"]:\n            raise OCIError(\n                status_code=400,\n                message=f\"Content type `{item_type}` is not supported by OCI\",\n            )\n\n        if item_type == \"text\":\n            text = content_item.get(\"text\")\n            if not isinstance(text, str):\n                raise OCIError(\n                    status_code=400,\n                    message=\"Content item of type `text` must have a string `text` field\",\n                )\n            new_content.append(OCITextContentPart(text=text))\n","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/oci/chat/generic.py#L58-L94","documentation":"In the OCI GENERIC message adapter, every content-part dict must carry a string 'type' field identifying it as text or image_url. If 'type' is missing, None, or not a string, OCIError(400) 'Each content item must have a string `type` field' is raised during request construction. The validation happens locally, so no tokens are spent.","triggerScenarios":"Passing a content part like {'text':'hi'} (type omitted), {'type':None,...}, or a part where 'type' was set from an untyped variable that ended up non-string, in a message sent to an oci/ GENERIC model.","commonSituations":"Hand-building content parts and forgetting the discriminator; migrating code from an API that infers the part type from keys; data-driven prompts where a template leaves 'type' empty for some rows.","solutions":["Add an explicit string 'type' to every part: 'text' or 'image_url'.","Validate messages with a small pre-flight check (see defense) that asserts each part has isinstance(part.get('type'), str).","Generate parts through one helper function so the discriminator is always set."],"exampleFix":"# before\ncontent=[{'text':'hello'}, {'type':'image_url','image_url':{'url':u}}]\n\n# after\ncontent=[{'type':'text','text':'hello'}, {'type':'image_url','image_url':{'url':u}}]","handlingStrategy":"type-guard","validationCode":"for i, part in enumerate(content):\n    assert isinstance(part.get('type'), str), f'content[{i}] missing string type: {part!r}'","typeGuard":"def has_string_type(part: object) -> bool:\n    \"\"\"True when part is a dict carrying a string 'type' discriminator.\"\"\"\n    return isinstance(part, dict) and isinstance(part.get('type'), str)","tryCatchPattern":"try:\n    litellm.completion(model='oci/...', messages=msgs)\nexcept OCIError as e:\n    if 'string `type` field' in str(e):\n        msgs = add_missing_types(msgs)\n    raise","preventionTips":["Never hand-write content parts without a typed constructor like text_part(s) / image_part(url).","Lint message payloads in tests with a schema check before they reach litellm."],"tags":["oci","input-validation","content-parts","openai-compat"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}