BerriAI/litellm · error · ValueError

purpose is required

Error message

purpose is required

What it means

The Bedrock create-file handler requires a non-None 'purpose' field alongside 'file'; it determines the S3 object naming strategy (batch JSONL parsing vs generic managed name). data.get('purpose') returned None.

Source

Thrown at litellm/llms/bedrock/files/transformation.py:347

        Get the complete S3 URL for the file upload request
        """
        request_params: Final = merge_bedrock_aws_request_params(litellm_params, optional_params)
        bucket_name = litellm_params.get("s3_bucket_name") or os.getenv("AWS_S3_BUCKET_NAME")
        if not bucket_name:
            raise ValueError(
                "S3 bucket_name is required. Set 's3_bucket_name' in litellm_params or AWS_S3_BUCKET_NAME env var"
            )
        bucket_name, object_prefix = split_configured_cloud_bucket_name(bucket_name)

        s3_region_name: Final = litellm_params.get("s3_region_name") or optional_params.get("s3_region_name")
        aws_region_name: Final = s3_region_name or self._get_aws_region_name(request_params, model)

        file_data: Final = data.get("file")
        purpose: Final = data.get("purpose")
        if file_data is None:
            raise ValueError("file is required")
        if purpose is None:
            raise ValueError("purpose is required")
        extracted_file_data: Final = extract_file_data(file_data)
        object_name = self.get_object_name(extracted_file_data, purpose)
        if object_prefix:
            object_name = f"{object_prefix}/{object_name}"
        encoded_object_name: Final = encode_s3_object_key_for_url(object_name)

        # S3 endpoint URL format
        s3_endpoint_url: Final = (
            request_params.get("s3_endpoint_url") or f"https://s3.{aws_region_name}.amazonaws.com"
        ).rstrip("/")

        return f"{s3_endpoint_url}/{bucket_name}/{encoded_object_name}"

    def get_supported_openai_params(self, model: str) -> list[OpenAICreateFileRequestOptionalParams]:
        return []

    def map_openai_params(
        self,

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Include purpose='batch' (or the supported value) as a form field in the multipart request.
  2. Verify field name casing/spelling is exactly 'purpose'.
  3. For batch use, ensure the file is valid JSONL so naming proceeds.

Example fix

# before
requests.post(url, files={"file": f})

# after
requests.post(url, files={"file": f}, data={"purpose": "batch"})
Defensive patterns

Strategy: validation

Validate before calling

assert data.get("purpose") is not None, "form field 'purpose' is required"

Try / catch

try:
    resp = litellm.create_file(file=f, purpose="batch")
except ValueError as e:
    if "purpose is required" in str(e):
        return HTTP 400
    raise

Prevention

When it happens

Trigger: Multipart upload with the file part but the 'purpose' form field omitted, or sent under a different field name (e.g. 'purposes') or inside JSON where form parsing ignores it.

Common situations: Clients forwarding only the file; form field name typos; OpenAI-compatible clients that assume purpose is optional.

Related errors


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