{"record":{"id":"a510e4650d8e38b7","repo":"quickwit-oss/quickwit","slug":"the-returned-multipart-upload-id-was-null","errorCode":null,"errorMessage":"the returned multipart upload id was null","messagePattern":"the returned multipart upload id was null","errorType":"exception","errorClass":"StorageError","httpStatus":null,"severity":"error","filePath":"quickwit/quickwit-storage/src/object_storage/s3_compatible_storage.rs","lineNumber":478,"sourceCode":"        .map_err(|error| error.into_inner())?;\n        Ok(())\n    }\n\n    async fn create_multipart_upload(&self, key: &str) -> StorageResult<MultipartUploadId> {\n        let upload_id = aws_retry(&self.retry_params, || async {\n            self.s3_client\n                .create_multipart_upload()\n                .bucket(self.bucket.clone())\n                .set_checksum_algorithm(aws_checksum_algorithm(self.checksum_algorithm))\n                .key(key)\n                .send()\n                .await\n        })\n        .await?\n        .upload_id\n        .ok_or_else(|| {\n            StorageErrorKind::Internal\n                .with_error(anyhow!(\"the returned multipart upload id was null\"))\n        })?;\n        Ok(MultipartUploadId(upload_id))\n    }\n\n    /// Returns the MD5 of the byte range when the configured strategy is\n    /// [`ChecksumAlgorithm::Md5`], otherwise `None` (no I/O performed).\n    async fn maybe_compute_part_md5(\n        &self,\n        payload: &dyn crate::PutPayload,\n        range: Range<u64>,\n    ) -> io::Result<Option<md5::Digest>> {\n        if !self.checksum_algorithm.is_md5() {\n            return Ok(None);\n        }\n        let read = payload.range_byte_stream(range).await?.into_async_read();\n        Ok(Some(compute_md5(read).await?))\n    }\n","sourceCodeStart":460,"sourceCodeEnd":496,"githubUrl":"https://github.com/quickwit-oss/quickwit/blob/a39730c5cdcd1a4fe798403737ae293999ea21f8/quickwit/quickwit-storage/src/object_storage/s3_compatible_storage.rs#L460-L496","documentation":"When starting an S3 multipart upload, the SDK's CreateMultipartUpload response must contain an `upload_id`. Quickwit unwraps it with `ok_or_else` and raises an Internal storage error if S3 returned null. This is an unexpected API response from the object store, since a successful create always carries an id.","triggerScenarios":"Calling `put_multipart` on S3CompatibleStorage when the CreateMultipartUpload response completes but has `upload_id: None` — typically caused by a proxy/MinIO/non-AWS S3-compatible service returning a malformed or non-standard response body.","commonSituations":"Using a buggy S3-compatible backend (MinIO, Ceph, vendor proxies) that strips or misparses the UploadResult XML; an intermediary (corporate proxy, some gateways) rewriting the response; SDK version parsing changes.","solutions":["Check the object storage backend and any proxies in front of it for malformed CreateMultipartUpload responses (inspect with verbose/logging mode)","Upgrade or reconfigure the S3-compatible service (e.g. newer MinIO) to a version with correct XML responses","Retry the upload; if persistent, switch endpoint or use non-multipart (smaller) uploads to isolate the issue","Report the backend's raw response if it consistently omits upload_id"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"let upload = loop {\n    match storage.put_multipart(&path).await {\n        Ok(u) => break u,\n        Err(e) if e.kind() == StorageErrorKind::Internal && attempts < 3 => { attempts += 1; continue; }\n        Err(e) => return Err(e.into()),\n    }\n};","preventionTips":["Test multipart uploads against your exact S3-compatible backend (MinIO/Ceph/proxies) before production","Keep the object-store SDK and backend versions current","Avoid custom response-rewriting proxies in the storage path","Monitor for repeated Internal errors on create_multipart_upload and capture raw responses"],"tags":["s3","multipart-upload","storage","unexpected-response"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"a39730c5cdcd1a4fe798403737ae293999ea21f8","analyzedAt":"2026-09-08T13:19:37.784Z","contentChangedAt":"2026-09-08T13:19:37.784Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}