{"record":{"id":"144119abdeb3140d","repo":"payloadcms/payload","slug":"failed-to-initialize-multipart-upload","errorCode":null,"errorMessage":"Failed to initialize multipart upload","messagePattern":"Failed to initialize multipart upload","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/storage-r2/src/client/R2ClientUploadHandler.ts","lineNumber":50,"sourceCode":"\n    const params: R2StorageMultipartUploadHandlerParams = {\n      collection: collectionSlug,\n      docPrefix: sanitizedDocPrefix,\n      fileName: file.name,\n      fileType: file.type,\n    }\n    const baseURL = formatAdminURL({\n      apiRoute,\n      path: endpointPath,\n      serverURL,\n    })\n\n    const getEndpoint = () => `${baseURL}?${String(new URLSearchParams(params))}`\n\n    // Initialize the multipart upload.\n    const multipart = await fetch(getEndpoint(), { method: 'POST' })\n    if (!multipart.ok) {\n      throw new Error('Failed to initialize multipart upload')\n    }\n\n    const { filename: sanitizedFilename, ...multipartUpload } = (await multipart.json()) as {\n      filename?: string\n    } & Pick<R2MultipartUpload, 'key' | 'uploadId'>\n\n    if (sanitizedFilename && sanitizedFilename !== file.name) {\n      updateFilename(sanitizedFilename)\n    }\n\n    const multipartUploadedParts: R2UploadedPart[] = []\n\n    params.multipartId = multipartUpload.uploadId\n    params.multipartKey = multipartUpload.key\n\n    const partTotal = Math.ceil(file.size / chunkSize)\n\n    for (let part = 1; part <= partTotal; part++) {","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/storage-r2/src/client/R2ClientUploadHandler.ts#L32-L68","documentation":"A plain Error thrown client-side in R2ClientUploadHandler when the initial POST to the R2 multipart endpoint (the admin handler URL built from serverURL/apiRoute/endpointPath) returns a non-ok response. It is a generic client error with no HTTP status attached, surfaced from the browser/worker fetch that starts a multipart upload.","triggerScenarios":"The initialize POST returns any non-2xx: 401/403 (access denied — see errors 382/380/381), 404 (wrong serverURL/apiRoute/endpointPath), 500 (handler threw), or a network/CORS failure yielding response.ok === false.","commonSituations":"Misconfigured serverURL or apiRoute producing a 404; CORS not allowing the POST from the browser; the user's session expired so the handler returns Forbidden; reverse proxy rewriting the endpoint path; the R2 adapter handler is not mounted at the expected route.","solutions":["Open the failing POST URL in the network tab and read the actual status/body — most likely 403 (auth) or 404 (route).","Verify serverURL, apiRoute, and the endpoint path resolve to the mounted R2 multipart handler.","Ensure the user is authenticated and the collection allows their create access.","Add CORS headers / credentials so the browser fetch is not blocked."],"exampleFix":"// before\nconst multipart = await fetch(getEndpoint(), { method: 'POST' })\nif (!multipart.ok) {\n  throw new Error('Failed to initialize multipart upload')\n}\n\n// after — surface the server's error body for diagnosis\nconst multipart = await fetch(getEndpoint(), { method: 'POST', credentials: 'include' })\nif (!multipart.ok) {\n  const body = await multipart.text().catch(() => '<no body>')\n  throw new Error(`Failed to initialize multipart upload (${multipart.status}): ${body}`)\n}","handlingStrategy":"try-catch","validationCode":"function endpointLooksValid(baseURL: string): boolean {\n  try {\n    const u = new URL(baseURL)\n    return u.protocol === 'http:' || u.protocol === 'https:'\n  } catch {\n    return false\n  }\n}\n\nif (!endpointLooksValid(baseURL)) {\n  throw new Error(`Invalid multipart endpoint URL: ${baseURL}`)\n}","typeGuard":"function isFetchError(err: unknown): err is Error {\n  return err instanceof Error && /multipart/i.test(err.message)\n}","tryCatchPattern":"try {\n  await handler.upload(file)\n} catch (err) {\n  if (err instanceof Error && /initialize multipart/i.test(err.message)) {\n    // inspect last network response, re-auth, or surface retry\n    showRetryUploadUI()\n    return\n  }\n  throw err\n}","preventionTips":["Verify serverURL/apiRoute/endpointPath resolve to the mounted R2 handler before upload.","Ensure credentials are included and CORS allows the POST.","Log the underlying response status before throwing so failures are diagnosable."],"tags":["r2-storage","upload","client","network","multipart"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}