{"record":{"id":"86f7c42c4f125070","repo":"BerriAI/litellm","slug":"prop-value-name-is-not-a-string","errorCode":null,"errorMessage":"Prop `{value_name}` is not a string","messagePattern":"Prop `(.+?)` is not a string","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"litellm/llms/bytez/chat/transformation.py","lineNumber":407,"sourceCode":"        for content_item in content:\n            type: str | None = content_item.get(\"type\")\n\n            if not type:\n                raise Exception(\"Prop `type` is not a string\")\n\n            content_item_map = open_ai_to_bytez_content_item_map[type]\n\n            if not content_item_map:\n                raise Exception(f\"Prop `{type}` is not supported\")\n\n            new_type = content_item_map[\"type\"]\n\n            value_name = content_item_map[\"value_name\"]\n\n            value: str | None = content_item.get(value_name)\n\n            if not value:\n                raise Exception(f\"Prop `{value_name}` is not a string\")\n\n            new_content.append({\"type\": new_type, value_name: value})\n\n        new_messages.append({\"role\": role, \"content\": new_content})\n\n    return new_messages\n\n\n# \"content\": \"The cat ran so fast\"\n# becomes\n# \"content\": [{\"type\": \"text\", \"text\": \"The cat ran so fast\"}]\ndef _adapt_string_only_content_to_lists(messages: list[dict]):\n    new_messages: Final = []\n\n    for message in messages:\n        role = message.get(\"role\")\n        content = message.get(\"content\")\n","sourceCodeStart":389,"sourceCodeEnd":425,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/bytez/chat/transformation.py#L389-L425","documentation":"Thrown by the Bytez adapter when a mapped content item is missing its value field (e.g. a `text` item without `text`, an `image_url` item without `url`). The adapter looks up which property to read via `value_name` and refuses empty/missing values. Despite the wording, it fires for any falsy value (None, empty string), not just non-string types.","triggerScenarios":"Sending `{\"type\": \"image_url\"}` with no `url` key, `{\"type\": \"text\", \"text\": \"\"}`, or `{\"type\": \"input_audio\", \"input_audio\": {...}}` (wrong nesting — the adapter expects the value directly under the mapped key, e.g. `url`). Note `image_url` items must have `url` as a plain string sibling of `type`, and `text` items must have a non-empty `text`.","commonSituations":"Generating content parts dynamically and leaving fields empty; misunderstanding that Bytez expects `{\"type\": \"image\", \"url\": ...}`-shaped input rather than OpenAI's nested `{\"image_url\": {\"url\": ...}}` (the map reads `content_item.get(\"url\")` directly); whitespace-only strings pass but empty strings fail.","solutions":["Ensure each content item carries a non-empty value under the expected key: `text` for text, `url` for image_url/input_audio/video_url.","Flatten nested OpenAI structures before sending: `{\"type\": \"image_url\", \"url\": \"https://...\"}` instead of `{\"type\": \"image_url\", \"image_url\": {\"url\": ...}}`.","Add a pre-flight validator that rejects content items whose mapped value key is missing or empty.","Log the offending message before the call to identify which part is malformed."],"exampleFix":"// before\ncontent = [{\"type\": \"image_url\", \"image_url\": {\"url\": \"https://x/y.png\"}}]\n\n// after (value read directly from `url` key)\ncontent = [{\"type\": \"image_url\", \"url\": \"https://x/y.png\"}]","handlingStrategy":"validation","validationCode":"VALUE_KEY = {\"text\": \"text\", \"image_url\": \"url\", \"input_audio\": \"url\", \"video_url\": \"url\"}\n\ndef validate_bytez_content_values(content):\n    for part in content:\n        key = VALUE_KEY.get(part.get(\"type\"))\n        if key and not part.get(key):\n            raise ValueError(f\"content part of type {part['type']} missing non-empty '{key}'\")","typeGuard":"def has_bytez_value(part) -> bool:\n    key = {\"text\": \"text\", \"image_url\": \"url\", \"input_audio\": \"url\", \"video_url\": \"url\"}.get(part.get(\"type\"))\n    return key is not None and isinstance(part.get(key), str) and bool(part[key].strip())","tryCatchPattern":null,"preventionTips":["Flatten nested OpenAI shapes ({\"image_url\": {\"url\": ...}}) to a top-level `url` before Bytez calls.","Never emit content parts with empty string values; skip them instead.","Assert part shape in dev builds with a schema check."],"tags":["bytez","multimodal","content-parts","request-validation"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}