BerriAI/litellm · error · Exception
Prop `{value_name}` is not a string
Error message
Prop `{value_name}` is not a string What it means
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.
Source
Thrown at litellm/llms/bytez/chat/transformation.py:407
for content_item in content:
type: str | None = content_item.get("type")
if not type:
raise Exception("Prop `type` is not a string")
content_item_map = open_ai_to_bytez_content_item_map[type]
if not content_item_map:
raise Exception(f"Prop `{type}` is not supported")
new_type = content_item_map["type"]
value_name = content_item_map["value_name"]
value: str | None = content_item.get(value_name)
if not value:
raise Exception(f"Prop `{value_name}` is not a string")
new_content.append({"type": new_type, value_name: value})
new_messages.append({"role": role, "content": new_content})
return new_messages
# "content": "The cat ran so fast"
# becomes
# "content": [{"type": "text", "text": "The cat ran so fast"}]
def _adapt_string_only_content_to_lists(messages: list[dict]):
new_messages: Final = []
for message in messages:
role = message.get("role")
content = message.get("content")
View on GitHub (pinned to 6c2dcb801b)
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.
Example fix
// before
content = [{"type": "image_url", "image_url": {"url": "https://x/y.png"}}]
// after (value read directly from `url` key)
content = [{"type": "image_url", "url": "https://x/y.png"}] Defensive patterns
Strategy: validation
Validate before calling
VALUE_KEY = {"text": "text", "image_url": "url", "input_audio": "url", "video_url": "url"}
def validate_bytez_content_values(content):
for part in content:
key = VALUE_KEY.get(part.get("type"))
if key and not part.get(key):
raise ValueError(f"content part of type {part['type']} missing non-empty '{key}'") Type guard
def has_bytez_value(part) -> bool:
key = {"text": "text", "image_url": "url", "input_audio": "url", "video_url": "url"}.get(part.get("type"))
return key is not None and isinstance(part.get(key), str) and bool(part[key].strip()) Prevention
- 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.
When it happens
Trigger: 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`.
Common situations: 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.
Related errors
- Prop `{type}` is not supported
- Prop `type` is not a string
- `content` can only contain strings or openai content dicts
- Content must be a string
- {custom_llm_provider.capitalize()}Exception - {error_str}
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/86f7c42c4f125070.
Report an issue: GitHub.