BerriAI/litellm · error · ValueError

Failed to download file from S3: {s3_uri}. Error: {e}

Error message

Failed to download file from S3: {s3_uri}. Error: {e}

What it means

While streaming the object from S3 via boto3 get_object, any exception (NoSuchKey, AccessDenied, invalid bucket, network error) is caught and re-raised as ValueError with the s3_uri and underlying error text. The original boto3 error type is lost, but its message is preserved.

Source

Thrown at litellm/llms/bedrock/files/handler.py:133

            aws_sts_endpoint=optional_params.get("aws_sts_endpoint"),
        )

        # Create S3 client
        s3_client: Final = boto3.client(
            "s3",
            aws_access_key_id=credentials.access_key,
            aws_secret_access_key=credentials.secret_key,
            aws_session_token=credentials.token,
            region_name=aws_region_name,
            verify=self._get_ssl_verify(),
        )

        # Download file from S3
        try:
            response: Final = s3_client.get_object(Bucket=bucket_name, Key=object_key)
            file_content: Final = response["Body"].read()
        except Exception as e:
            raise ValueError(f"Failed to download file from S3: {s3_uri}. Error: {e}")

        # Create mock HTTP response
        mock_response: Final = httpx.Response(
            status_code=200,
            content=file_content,
            headers={"content-type": "application/octet-stream"},
            request=httpx.Request(method="GET", url=s3_uri),
        )

        return HttpxBinaryResponseContent(response=mock_response)

    def file_content(
        self,
        _is_async: bool,
        file_content_request: FileContentRequest,
        api_base: str | None,
        optional_params: dict,
        timeout: float | httpx.Timeout,

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Read the embedded 'Error: {e}' text — NoSuchKey vs AccessDenied dictates the fix.
  2. Verify the object exists: aws s3 ls <s3_uri> with the same credentials.
  3. Grant s3:GetObject on the bucket/prefix to the role in use.
  4. Confirm AWS_S3_BUCKET_NAME / s3_bucket_name config matches the bucket files were uploaded to.
Defensive patterns

Strategy: try-catch

Validate before calling

def object_exists(s3_client, bucket: str, key: str) -> bool:
    try:
        s3_client.head_object(Bucket=bucket, Key=key)
        return True
    except Exception:
        return False

Try / catch

try:
    content = handler.file_content(request, ...)
except ValueError as e:
    if "Failed to download file from S3" in str(e):
        if "NoSuchKey" in str(e): return HTTP 404
        if "AccessDenied" in str(e): return HTTP 403 / alert
        raise

Prevention

When it happens

Trigger: GET /files/{id}/content where the object was deleted from the bucket, the credentials lack s3:GetObject, the bucket belongs to another account, or the configured region/endpoint for the S3 client is wrong.

Common situations: Lifecycle rules deleting old uploads; wrong AWS_S3_BUCKET_NAME env var pointing at a bucket without the object; cross-account buckets without object ownership/ACL grants; files created before a bucket migration.

Related errors


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