BerriAI/litellm · error · ValueError
input must be a string or a list
Error message
input must be a string or a list
What it means
ValueError from CachingHandler.handle_kwargs_input_list_or_str: kwargs['input'] is neither a str nor a list. LiteLLM's embedding cache layer normalizes input by wrapping a string into a one-element list and passing lists through; any other type (None, int, dict) fails the isinstance chain and is rejected.
Source
Thrown at litellm/caching/caching_handler.py:378
self.preset_cache_key
or self.request_kwargs.get("cache_key")
or litellm.cache.get_cache_key(**self.request_kwargs)
)
if hasattr(cached_result, "_hidden_params"):
cached_result._hidden_params["cache_key"] = cache_key
return CachingHandlerResponse(cached_result=cached_result)
return CachingHandlerResponse(cached_result=cached_result)
def handle_kwargs_input_list_or_str(self, kwargs: dict[str, Any]) -> list[str]:
"""
Handles the input of kwargs['input'] being a list or a string
"""
if isinstance(kwargs["input"], str):
return [kwargs["input"]]
elif isinstance(kwargs["input"], list):
return kwargs["input"]
else:
raise ValueError("input must be a string or a list")
def _extract_model_from_cached_results(self, non_null_list: list[tuple[int, CachedEmbedding]]) -> str | None:
"""
Helper method to extract the model name from cached results.
Args:
non_null_list: List of (idx, cr) tuples where cr is the cached result dict
Returns:
Optional[str]: The model name if found, None otherwise
"""
for _, cr in non_null_list:
if isinstance(cr, dict) and cr.get("model"):
return cr["model"]
return None
def _process_async_embedding_cached_response(
self,View on GitHub (pinned to 6c2dcb801b)
Solutions
- Convert before calling: wrap strings as-is, convert arrays with input=list(arr), and ensure input is never None.
- For token ids, pass a list of ints (list[list[int]] for multiple inputs).
- Add a type check at your call site for data sourced from users/pipelines.
Example fix
# before litellm.embedding(model="text-embedding-3-small", input=np.array([1,2,3])) # after litellm.embedding(model="text-embedding-3-small", input=list(np.array([1,2,3])))
Defensive patterns
Strategy: type-guard
Validate before calling
if not isinstance(user_input, (str, list)):
user_input = list(user_input) if hasattr(user_input, "__iter__") else [user_input] Type guard
def is_valid_embedding_input(v) -> bool:
return isinstance(v, (str, list)) Prevention
- Normalize all embedding inputs through one helper that enforces str|list.
- Reject None and exotic types at the API boundary of your service.
- Convert numpy/torch arrays with .tolist() before calling LiteLLM.
When it happens
Trigger: Calling litellm.embedding (or aembedding) with caching enabled where input is not a string or list — e.g. input=None, input=12345 (token ids as a plain int, not wrapped in a list), or a numpy array/tensor passed directly.
Common situations: Passing token-id arrays (list-of-ints is fine, but a bare numpy array/torch tensor is not); a None default leaking from upstream config; passing bytes or other exotic payload types.
Related errors
- LLM client cache lazy import: unknown attribute {name!r}
- Invalid value passed in for aget_assistants. Only bool or No
- Invalid value passed in for async_create_assistants. Only bo
- Invalid value passed in for async_delete_assistants. Only bo
- 'models' must be a string or list of strings
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/5dccdfbfbf453379.
Report an issue: GitHub.