BerriAI/litellm · warning · ValueError

Input must be a list of strings

Error message

Input must be a list of strings

What it means

The Cohere-on-SageMaker embedding config validates that input is either a single string or a flat list of strings. If the list's first element is itself a list or an int, it raises ValueError before any request is sent, because the Cohere SageMaker endpoint only accepts an array of strings.

Source

Thrown at litellm/llms/sagemaker/embedding/cohere_transformation.py:75

    def get_error_class(self, error_message: str, status_code: int, headers: dict | Headers) -> BaseLLMException:
        return SagemakerError(message=error_message, status_code=status_code, headers=headers)

    def transform_embedding_request(
        self,
        model: str,
        input: "AllEmbeddingInputValues",
        optional_params: dict,
        headers: dict,
    ) -> dict:
        """
        Transform embedding request for Cohere models on SageMaker
        """
        if isinstance(input, str):
            input_list: list[str] = [input]
        elif isinstance(input, list):
            if input and (isinstance(input[0], list) or isinstance(input[0], int)):
                raise ValueError("Input must be a list of strings")
            input_list = cast(list[str], input)
        else:
            input_list = [str(input)]

        return dict(
            BedrockCohereEmbeddingConfig()._transform_request(
                model=model,
                input=input_list,
                inference_params=optional_params,
            )
        )

    def transform_embedding_response(
        self,
        model: str,
        raw_response: Response,
        model_response: "EmbeddingResponse",
        logging_obj: Any,

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Pass a flat list of strings: input=['doc one', 'doc two'], or a single string.
  2. If inputs arrive nested, flatten one level before calling: input=[t for row in inputs for t in row] or drop the outer list.
  3. If you have token ids, decode them back to text before calling the embedding endpoint.

Example fix

# before
litellm.embedding(model='sagemaker/cohere-embed-english-v3', input=[[1, 2, 3], [4, 5, 6]])
# after
litellm.embedding(model='sagemaker/cohere-embed-english-v3', input=['hello world', 'second doc'])
Defensive patterns

Strategy: type-guard

Validate before calling

def flatten_embedding_inputs(x) -> list[str]:
    if isinstance(x, str):
        return [x]
    if isinstance(x, list):
        flat = []
        for item in x:
            if isinstance(item, list):
                flat.extend(str(i) for i in item)
            else:
                flat.append(str(item))
        return flat
    return [str(x)]

Type guard

from typing import Any

def is_flat_str_list(v: Any) -> bool:
    return isinstance(v, list) and len(v) > 0 and all(isinstance(i, str) for i in v)

Prevention

When it happens

Trigger: Calling litellm.embedding(model='sagemaker/<cohere-embed-...>', input=[[...tokens...], ...]) with pre-tokenized int lists, or nested batches like input=[['a', 'b'], ['c']].

Common situations: Porting code from OpenAI-style token-array inputs (list of int token ids); passing a numpy array converted via .tolist() that yields nested lists; batch helpers that wrap inputs one level too deep.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/c5e4d90bf6b48af5. Report an issue: GitHub.