transloadit/uppy · error
s3: the object key must be passed as a query parameter. For
Error message
s3: the object key must be passed as a query parameter. For example: "?key=abc.jpg"
What it means
The GET /s3/multipart/:uploadId endpoint (listing already uploaded parts) requires the S3 object key to be passed as the key query parameter so Companion knows which object the uploadId belongs to. Without a string key, Companion returns HTTP 400 with this message including the expected format ?key=abc.jpg.
Source
Thrown at packages/@uppy/companion/src/server/controllers/s3.ts:271
* - PartNumber - the index of this part.
* - ETag - a hash of this part's contents, used to refer to it.
* - Size - size of this part.
*/
function getUploadedParts(req: Request, res: Response, next: NextFunction) {
const client = getS3Client(req, res)
if (!client) return
const s3Client = client
const { uploadId } = req.params
const { key } = req.query
assert(
typeof uploadId === 'string' && uploadId.length > 0,
's3: uploadId must be provided.',
)
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
}
const keyStr = key
const bucket = getBucket({ bucketOrFn: config.bucket, req })
const parts: Part[] = []
const listPartsPage = (startAt?: string) => {
s3Client
.send(
new ListPartsCommand({
Bucket: bucket,
Key: keyStr,
UploadId: uploadId,View on GitHub (pinned to 5d4dedd02a)
Solutions
- Append the object key as a query parameter: GET /s3/multipart/${encodeURIComponent(uploadId)}?key=${encodeURIComponent(key)}.
- Make sure you only send the key once in the query string (duplicate ?key= values become an array and fail the typeof string check).
- Keep the key returned by the create-multipart-upload / getKey step and reuse it verbatim for subsequent part calls.
Example fix
// before
fetch(`${companionUrl}/s3/multipart/${uploadId}`)
// after
fetch(
`${companionUrl}/s3/multipart/${encodeURIComponent(uploadId)}` +
`?key=${encodeURIComponent(key)}`,
) Defensive patterns
Strategy: validation
Validate before calling
const url =
`${companion}/s3/multipart/${encodeURIComponent(uploadId)}` +
`?key=${encodeURIComponent(key)}` Type guard
function hasKeyParam(key: unknown): key is string {
return typeof key === 'string' && key.length > 0
} Try / catch
if (res.status === 400) {
const body = await res.json()
if (body.error.includes('object key must be passed')) {
throw new Error(`Missing ?key= for uploadId ${uploadId}`)
}
} Prevention
- Centralize URL building for multipart endpoints in one helper that always appends key
- encodeURIComponent the key — encoded values still pass the string check
- Persist the key returned at creation and pass it to every subsequent call
When it happens
Trigger: Calling GET /s3/multipart/<uploadId> without a ?key=... query string, or with key passed in the body or headers instead of the query string, or as an array (?key=a&key=b) which Express parses into a non-string.
Common situations: Custom clients that only pass uploadId in the URL and forget the key; refactors that move the key into a header; duplicate query parameters causing Express to yield an array.
Related errors
- s3: the part numbers must be passed as a comma separated que
- s3: content type must be a string
- s3: uploadId must be provided.
- s3: the part number must be a number between 1 and 10000.
- s3: the part numbers must be a number between 1 and 10000.
AI-assisted analysis of transloadit/uppy@5d4dedd02a (2026-08-28).
Data as JSON: /api/errors/3689ca48169d12e7.
Report an issue: GitHub.