{"record":{"id":"fae6818f7632da4c","repo":"BerriAI/litellm","slug":"unable-to-parse-s3-url-https-url","errorCode":null,"errorMessage":"Unable to parse S3 URL: {https_url}","messagePattern":"Unable to parse S3 URL: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/llms/bedrock/files/transformation.py","lineNumber":1129,"sourceCode":"            key = unquote(key)\n            s3_uri = f\"s3://{bucket}/{key}\"\n        elif match2:\n            # Pattern: https://bucket.s3.region.amazonaws.com/key\n            bucket, region, key = match2.groups()\n            key = unquote(key)\n            s3_uri = f\"s3://{bucket}/{key}\"\n        else:\n            # Fallback: try to extract bucket and key from URL path\n            from urllib.parse import urlparse\n\n            parsed: Final = urlparse(https_url)\n            path_parts: Final = parsed.path.lstrip(\"/\").split(\"/\", 1)\n            if len(path_parts) >= 2:\n                bucket, key = path_parts[0], path_parts[1]\n                key = unquote(key)\n                s3_uri = f\"s3://{bucket}/{key}\"\n            else:\n                raise ValueError(f\"Unable to parse S3 URL: {https_url}\")\n\n        # Extract filename from key\n        filename: Final = key.split(\"/\")[-1] if \"/\" in key else key\n\n        return s3_uri, filename\n\n    def transform_create_file_response(\n        self,\n        model: str | None,\n        raw_response: Response,\n        logging_obj: LiteLLMLoggingObj,\n        litellm_params: dict,\n    ) -> OpenAIFileObject:\n        \"\"\"\n        Transform S3 File upload response into OpenAI-style FileObject\n        \"\"\"\n        # Use the actual upload URL that was used for the S3 upload\n        upload_url: Final = litellm_params.get(\"upload_url\")","sourceCodeStart":1111,"sourceCodeEnd":1147,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/llms/bedrock/files/transformation.py#L1111-L1147","documentation":"After the S3 PUT, transform_create_file_response converts the upload URL back into the s3:// URI that becomes the file id. Two regexes handle path-style (https://s3.region.amazonaws.com/bucket/key) and virtual-hosted (https://bucket.s3.region.amazonaws.com/key) amazonaws URLs; a fallback parses bucket/key from the URL path. If the path has fewer than two segments (no /bucket/key), parsing fails.","triggerScenarios":"An upload URL whose path lacks bucket+key: an empty object key (bucket name configured but object name empty), a custom s3_endpoint_url that returns a host-only or bucket-only URL, or a non-amazonaws virtual-hosted endpoint where the bucket lives in the hostname and the path holds only the key.","commonSituations":"Custom S3-compatible endpoints (MinIO, LocalStack, corporate S3 gateways) that do not match the amazonaws regexes; trailing configuration mistakes where s3_bucket_name swallows the key; proxy configs rewriting the upload URL.","solutions":["Verify s3_bucket_name / object naming so the final URL is endpoint/bucket/key with a non-empty key","For custom endpoints, use path-style addressing so bucket and key both appear in the URL path","Log litellm_params['upload_url'] after create to see the exact URL the parser rejected","If the URL looks valid but non-amazonaws, report it as a parser gap at github.com/BerriAI/litellm/issues"],"exampleFix":"# before: proxy config\ngeneral_settings:\n  s3_bucket_name: \"my-bucket\"   # object key generated empty due to misconfigured upload_url\n\n# after: ensure upload URL is path-style with bucket+key\n# e.g. https://s3.us-west-2.amazonaws.com/my-bucket/path/to/file.jsonl","handlingStrategy":"try-catch","validationCode":"from urllib.parse import urlparse\n\ndef upload_url_is_parseable(url: str) -> bool:\n    p = urlparse(url)\n    return p.hostname and len(p.path.lstrip(\"/\").split(\"/\", 1)) >= 2 and all(p.path.lstrip(\"/\").split(\"/\", 1))","typeGuard":null,"tryCatchPattern":"try:\n    file_obj = await client.files.create(file=f, purpose=\"batch\")\nexcept ValueError as e:\n    if \"Unable to parse S3 URL\" in str(e):\n        # inspect litellm_params['upload_url']: custom endpoint or empty object key\n        raise RuntimeError(f\"upload URL not in endpoint/bucket/key form: {e}\") from e\n    raise","preventionTips":["Configure custom S3 endpoints to use path-style URLs so bucket and key are both in the path","Ensure bucket and object-key configuration always yields a non-empty key","Smoke-test one create_file per environment to catch endpoint-shape issues at deploy time"],"tags":["bedrock","s3","url-parsing","files-api","litellm"],"backgroundTag":"url-parsing-failed","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}