transloadit/uppy · critical · TypeError
s3: bucket key must be a string or a function resolving the
Error message
s3: bucket key must be a string or a function resolving the bucket string
What it means
For S3 uploads, Companion resolves the target bucket from options.s3.bucket, which may be a static string or a function of ({req, metadata, filename}). After resolution, if the result is not a non-empty string, Companion throws this TypeError because it has no valid bucket to upload to — the code itself flags it as a misconfiguration or bug.
Source
Thrown at packages/@uppy/companion/src/server/helpers/utils.ts:280
export const getBucket = ({
bucketOrFn,
req,
metadata,
filename,
}: {
bucketOrFn: string | GetBucketFn | undefined
req: Request
metadata?: Record<string, unknown>
filename?: string
}): string => {
const bucket =
typeof bucketOrFn === 'function'
? bucketOrFn({ req, metadata: metadata ?? {}, filename })
: bucketOrFn
if (typeof bucket !== 'string' || bucket === '') {
// This means a misconfiguration or bug
throw new TypeError(
's3: bucket key must be a string or a function resolving the bucket string',
)
}
return bucket
}
export const truncateFilename = (
filename: string,
maxFilenameLength?: number,
): string => {
if (
maxFilenameLength == null ||
!Number.isFinite(maxFilenameLength) ||
maxFilenameLength <= 0
) {
// Historically, passing `undefined` resulted in no truncation (slice(0)).
return filename
}View on GitHub (pinned to 5d4dedd02a)
Solutions
- Set providerOptions.s3.bucket to a literal bucket name: bucket: 'my-uploads'
- If dynamic, make the function always return a string: bucket: ({ req, metadata }) => req.headers['x-upload-bucket'] ?? 'default-uploads'
- Check the env vars / inputs the bucket function reads are actually present at request time
- Add a startup assertion that validates the resolved bucket is a non-empty string
Example fix
// before
providerOptions: {
s3: { bucket: ({ req }) => req.headers['x-bucket'] }, // may be undefined
},
// after
providerOptions: {
s3: { bucket: ({ req }) => String(req.headers['x-bucket'] ?? 'default-uploads') },
}, Defensive patterns
Strategy: validation
Validate before calling
// Validate bucket config before starting upload flows
const bucket = typeof(s3Opts.bucket) === 'function'
? s3Opts.bucket({ req: mockReq, metadata: {}, filename: 'probe.txt' })
: s3Opts.bucket
if (typeof bucket !== 'string' || bucket === '') throw new TypeError('bad bucket config') Type guard
function isValidBucket(bucket: unknown): bucket is string {
return typeof bucket === 'string' && bucket.length > 0
} Prevention
- Always default dynamic bucket functions to a known bucket string
- Add a config validation step at Companion startup for providerOptions.s3
- Use TypeScript satisfies on your options object to catch wrong types at compile time
When it happens
Trigger: Configuring companionOptions.providerOptions.s3.bucket as undefined/null/a number, or a bucket function that returns undefined (e.g. reading from req.headers or metadata that is missing), or returns an empty string when resolving dynamically per-request.
Common situations: Missing/typo'd S3 env var used inside a bucket function (e.g. process.env.S3_BUCKET unset so it returns undefined), a bucket resolver that returns void on an unhandled code path, or copy-pasting config from an example that omits bucket.
Related errors
- The S3 client is not configured on this companion instance.
- s3: filename returned from `getKey` must be a string
- Missing S3 object key for completing multipart upload
- [s3mini] fileType must be a string
- S3 returned ${xhr.status}${serviceCode ? ` – ${serviceCode}`
AI-assisted analysis of transloadit/uppy@5d4dedd02a (2026-08-28).
Data as JSON: /api/errors/b1e8017260c58ac8.
Report an issue: GitHub.