BerriAI/litellm · error · ValueError

Invalid S3 URI format: {s3_uri}

Error message

Invalid S3 URI format: {s3_uri}

What it means

Raised by the Bedrock S3 URI parser when the supplied string does not start with the 's3://' scheme. LiteLLM requires canonical S3 URIs for Bedrock file transformations (document upload for converse APIs), and this is the first structural check. The same message is reused for a second failure where the remainder contains no '/' separator.

Source

Thrown at litellm/llms/bedrock/common_utils.py:1409

        if model.startswith("bedrock/"):
            return model[8:]  # Remove "bedrock/" prefix
        return model

    def parse_s3_uri(self, s3_uri: str) -> tuple:
        """
        Parse S3 URI into bucket and key components.

        Args:
            s3_uri: S3 URI (e.g., "s3://bucket/key/path")

        Returns:
            Tuple of (bucket, key)

        Raises:
            ValueError: If URI format is invalid
        """
        if not s3_uri.startswith("s3://"):
            raise ValueError(f"Invalid S3 URI format: {s3_uri}")

        s3_parts: Final = s3_uri[5:].split("/", 1)  # Remove "s3://" and split on first "/"
        if len(s3_parts) != 2:
            raise ValueError(f"Invalid S3 URI format: {s3_uri}")

        return s3_parts[0], s3_parts[1]  # bucket, key

    def extract_model_from_s3_file_path(self, s3_uri: str, optional_params: dict) -> str:
        """
        Extract model ID from S3 file path.

        The Bedrock file transformation creates S3 objects with the model name embedded:
        Format: s3://bucket/litellm-bedrock-files-{model}-{uuid}.jsonl
        """
        # Check if model is provided in optional_params first
        if "model" in optional_params and optional_params["model"]:
            return self.get_bedrock_model_id_from_litellm_model(optional_params["model"])

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Normalize the URI to the form s3://<bucket>/<key> before passing it to LiteLLM
  2. If the source is an AWS console link (https://s3.<region>.amazonaws.com/bucket/key), convert it to s3://bucket/key
  3. Validate user-supplied URIs with a regex or urllib.parse before they reach the Bedrock path

Example fix

// before
await client.messages.create(model=..., files=[{"file_data": "https://s3.us-east-1.amazonaws.com/mybucket/doc.json"}])

// after
await client.messages.create(model=..., files=[{"file_data": "s3://mybucket/doc.json"}])
Defensive patterns

Strategy: validation

Validate before calling

import re
S3_URI_RE = re.compile(r"^s3://[^/]+/.+$")

def is_valid_s3_uri(uri: str) -> bool:
    return isinstance(uri, str) and bool(S3_URI_RE.match(uri))

Type guard

def is_s3_uri(value: str) -> bool:
    return isinstance(value, str) and value.startswith("s3://") and "/" in value[5:]

Try / catch

try:
    bucket, key = parse_s3_uri(uri)
except ValueError as e:
    raise ValueError(f"Bad file reference '{uri}': expected s3://bucket/key") from e

Prevention

When it happens

Trigger: Passing an http(s) URL, local file path, bare bucket name, or a typo'd scheme (e.g. 'S3://bucket/key' with uppercase) anywhere LiteLLM expects an s3_uri for Bedrock file handling; calling parse on a string like 's3://bucketonly' (no key) hits the sibling check at line 1413.

Common situations: Copying a file URL from the AWS console (which is https), user-supplied file references not validated upstream, or building the URI by string concatenation that drops the scheme.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/5e6c63a49f7edb8d. Report an issue: GitHub.