payloadcms/payload · error
Failed to initialize multipart upload
Error message
Failed to initialize multipart upload
What it means
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.
Source
Thrown at packages/storage-r2/src/client/R2ClientUploadHandler.ts:50
const params: R2StorageMultipartUploadHandlerParams = {
collection: collectionSlug,
docPrefix: sanitizedDocPrefix,
fileName: file.name,
fileType: file.type,
}
const baseURL = formatAdminURL({
apiRoute,
path: endpointPath,
serverURL,
})
const getEndpoint = () => `${baseURL}?${String(new URLSearchParams(params))}`
// Initialize the multipart upload.
const multipart = await fetch(getEndpoint(), { method: 'POST' })
if (!multipart.ok) {
throw new Error('Failed to initialize multipart upload')
}
const { filename: sanitizedFilename, ...multipartUpload } = (await multipart.json()) as {
filename?: string
} & Pick<R2MultipartUpload, 'key' | 'uploadId'>
if (sanitizedFilename && sanitizedFilename !== file.name) {
updateFilename(sanitizedFilename)
}
const multipartUploadedParts: R2UploadedPart[] = []
params.multipartId = multipartUpload.uploadId
params.multipartKey = multipartUpload.key
const partTotal = Math.ceil(file.size / chunkSize)
for (let part = 1; part <= partTotal; part++) {View on GitHub (pinned to 00c58b35c0)
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.
Example fix
// before
const multipart = await fetch(getEndpoint(), { method: 'POST' })
if (!multipart.ok) {
throw new Error('Failed to initialize multipart upload')
}
// after — surface the server's error body for diagnosis
const multipart = await fetch(getEndpoint(), { method: 'POST', credentials: 'include' })
if (!multipart.ok) {
const body = await multipart.text().catch(() => '<no body>')
throw new Error(`Failed to initialize multipart upload (${multipart.status}): ${body}`)
} Defensive patterns
Strategy: try-catch
Validate before calling
function endpointLooksValid(baseURL: string): boolean {
try {
const u = new URL(baseURL)
return u.protocol === 'http:' || u.protocol === 'https:'
} catch {
return false
}
}
if (!endpointLooksValid(baseURL)) {
throw new Error(`Invalid multipart endpoint URL: ${baseURL}`)
} Type guard
function isFetchError(err: unknown): err is Error {
return err instanceof Error && /multipart/i.test(err.message)
} Try / catch
try {
await handler.upload(file)
} catch (err) {
if (err instanceof Error && /initialize multipart/i.test(err.message)) {
// inspect last network response, re-auth, or surface retry
showRetryUploadUI()
return
}
throw err
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Failed to upload part ${part} / ${partTotal}
- Failed to complete multipart upload
- Collection ${collectionSlug} was not found in R2 Storage opt
- Fetch failed with status: ${response.status}
- Too many redirects.
AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12).
Data as JSON: /api/errors/144119abdeb3140d.
Report an issue: GitHub.