transloadit/uppy · error
s3: uploadId must be provided.
Error message
s3: uploadId must be provided.
What it means
The part-upload signing endpoint POST /s3/multipart/:uploadId/:partNumber requires the route parameter uploadId to be a non-empty string. It is the AWS multipart upload ID returned when the multipart upload was created. If it's missing or empty, Companion returns HTTP 400 with this message.
Solutions
- Store the uploadId returned from the create-multipart response and include it in the URL: POST /s3/multipart/${uploadId}/${partNumber}?key=...
- Guard client-side: only start part uploads once uploadId is a non-empty string.
- Re-create the multipart upload (via POST /s3/multipart) if the uploadId was lost, and abort the stale one if known.
Example fix
// before
const url = `/s3/multipart/${upload?.id}/${partNumber}` // may be /s3/multipart/undefined/1
// after
if (!upload?.id) throw new Error('missing uploadId')
const url = `/s3/multipart/${upload.id}/${partNumber}` Defensive patterns
Strategy: validation
Validate before calling
if (typeof uploadId !== 'string' || uploadId.length === 0) {
throw new Error('Cannot sign part: multipart upload was not created yet')
}
const url = `/s3/multipart/${encodeURIComponent(uploadId)}/${partNumber}` Type guard
const hasUploadId = (u: unknown): u is string => typeof u === 'string' && u.length > 0
Try / catch
try {
const res = await signPart(...)
if (res.status === 400) handleBadRequest(await res.json())
} catch (e) {
// network-level errors only; 400s are handled above
} Prevention
- Create the multipart upload first and await its uploadId before scheduling parts
- Treat a missing uploadId as 'restart upload', not as a retryable error
- Store uploadId in durable state when uploads span page reloads
When it happens
Trigger: Calling the sign-part endpoint with an empty uploadId path segment (POST /s3/multipart//5), or with undefined/null interpolated into the URL by a client that lost track of the uploadId after creating the multipart upload.
Common situations: Client state lost between creating the multipart upload and uploading parts (page reload, component remount), or URL construction bugs where uploadId is undefined due to a typo or async race.
Related errors
- s3: content type must be a string
- s3: the object key must be passed as a query parameter. For…
- s3: the part number must be a number between 1 and 10000.
- s3: the part numbers must be a number between 1 and 10000.
- s3: the part numbers must be passed as a comma separated…
AI-assisted analysis of transloadit/uppy@5d4dedd02a (2026-08-28).
Data as JSON: /api/errors/2d2bab3df53f71d8.
Report an issue: GitHub.
Appendix: source
Thrown at packages/@uppy/companion/src/server/controllers/s3.ts:327
*
* Expected URL parameters:
* - uploadId - The uploadId returned from `createMultipartUpload`.
* - partNumber - This part's index in the file (1-10000).
* Expected query parameters:
* - key - The object key in the S3 bucket.
* Response JSON:
* - url - The URL to upload to, including signed query parameters.
*/
function signPartUpload(req: Request, res: Response, next: NextFunction) {
const client = getS3Client(req, res)
if (!client) return
const uploadId = req.params['uploadId']
const partNumber = req.params['partNumber']
const key = req.query['key']
if (typeof uploadId !== 'string' || uploadId.length === 0) {
res.status(400).json({ error: 's3: uploadId must be provided.' })
return
}
if (typeof key !== 'string') {
res.status(400).json({
error:
's3: the object key must be passed as a query parameter. For example: "?key=abc.jpg"',
})
return
}
if (typeof partNumber !== 'string' || !parseInt(partNumber, 10)) {
res.status(400).json({
error: 's3: the part number must be a number between 1 and 10000.',
})
return
}
const bucket = getBucket({ bucketOrFn: config.bucket, req })
View on GitHub (pinned to 5d4dedd02a)