transloadit/uppy · error
s3: the part numbers must be a number between 1 and 10000.
Error message
s3: the part numbers must be a number between 1 and 10000.
What it means
After parsing the comma-separated partNumbers query parameter, Companion validates every entry parses as an integer via parseInt. Any non-numeric token ('abc', '', 'null') fails and results in HTTP 400. AWS requires part numbers between 1 and 10000, which is the constraint the message refers to.
Source
Thrown at packages/@uppy/companion/src/server/controllers/s3.ts:409
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 partNumbers !== 'string') {
res.status(400).json({
error:
's3: the part numbers must be passed as a comma separated query parameter. For example: "?partNumbers=4,6,7,21"',
})
return
}
const partNumbersArray = partNumbers.split(',')
if (!partNumbersArray.every((partNumber) => parseInt(partNumber, 10))) {
res.status(400).json({
error: 's3: the part numbers must be a number between 1 and 10000.',
})
return
}
const bucket = getBucket({ bucketOrFn: config.bucket, req })
Promise.all(
partNumbersArray.map((partNumber) => {
return getSignedUrl(
client,
new UploadPartCommand({
Bucket: bucket,
Key: key,
UploadId: uploadId,
PartNumber: Number(partNumber),
Body: '',
}),View on GitHub (pinned to 5d4dedd02a)
Solutions
- Filter and validate before joining: parts.filter(Number.isInteger).join(',') with parts in the 1..10000 range.
- Check for 0-based indexing bugs — part numbers must start at 1.
- Log the outgoing query string to spot empty tokens like '1,,2' from sparse arrays.
Example fix
// before
const partNumbers = uploadedParts.map((p) => p.index).join(',') // may contain 0 or gaps
// after
const partNumbers = uploadedParts
.map((p) => p.index + 1)
.filter((n) => Number.isInteger(n) && n >= 1 && n <= 10000)
.join(',') Defensive patterns
Strategy: type-guard
Validate before calling
const validParts = parts.filter(
(n): n is number => Number.isInteger(n) && n >= 1 && n <= 10000,
)
const partNumbers = validParts.join(',') Type guard
const allValidParts = (arr: unknown[]): boolean => arr.length > 0 && arr.every((n) => Number.isInteger(n) && n >= 1 && n <= 10000)
Prevention
- Filter sparse arrays and non-integers before joining
- Guard against 0-based part indexes
- Clamp total parts to 10000 by raising chunk size
When it happens
Trigger: Sending ?partNumbers=1,2,foo or ?partNumbers=1,,2 (empty token), or interpolating undefined/null values into the joined string, e.g. [1, undefined, 3].join(',') producing '1,,3'.
Common situations: Building the part list from sparse arrays or filtered lists without removing holes; 0-based part indexes ('0' parses to 0 which is falsy and fails); string interpolation of unvalidated user input.
Related errors
- s3: the part number must be a number between 1 and 10000.
- s3: the part numbers must be passed as a comma separated que
- s3: content type must be a string
- s3: the object key must be passed as a query parameter. For
- s3: uploadId must be provided.
AI-assisted analysis of transloadit/uppy@5d4dedd02a (2026-08-28).
Data as JSON: /api/errors/5fab8d0ab5468642.
Report an issue: GitHub.