transloadit/uppy · critical · TypeError

signRequest must be a function

Error message

signRequest must be a function

What it means

S3mini validates that signRequest, when provided, is a function. Passing anything else (a string, object, or the result of calling the function instead of the function itself) throws this TypeError before any request is made.

Source

Thrown at packages/@uppy/aws-s3/src/s3-client/S3mini.ts:65

  private signRequest!: IT.SignRequestFn

  constructor({
    region = 'auto',
    requestSizeInBytes = C.DEFAULT_REQUEST_SIZE_IN_BYTES,
    requestAbortTimeout,
    ...rest
  }: IT.S3Config) {
    super({ requestAbortTimeout })
    if ('signRequest' in rest) {
      const { signRequest } = rest
      if (!signRequest) {
        throw new TypeError(
          'Either signRequest or getCredentials must be provided',
        )
      }

      if (signRequest && typeof signRequest !== 'function') {
        throw new TypeError('signRequest must be a function')
      }

      this.signRequest = signRequest
    } else if ('getCredentials' in rest) {
      const { getCredentials, endpoint } = rest
      if (typeof endpoint !== 'string' || endpoint.trim().length === 0) {
        throw new TypeError(C.ERROR_ENDPOINT_REQUIRED)
      }
      if (getCredentials && typeof getCredentials !== 'function') {
        throw new TypeError('getCredentials must be a function')
      }
      this.endpoint = new URL(this._ensureValidUrl(endpoint))

      this.getCredentials = getCredentials
      this.signRequest = this._createCredentialBasedSigner()
    } else {
      throw new TypeError(
        'Either signRequest or getCredentials must be provided',

View on GitHub (pinned to 5d4dedd02a)

Solutions

  1. Pass an async function receiving ({method, key, uploadId, partNumber}) and returning {url}
  2. If you meant client-side signing, pass endpoint plus getCredentials instead of a URL string
  3. Double-check you're passing the function reference, not its return value

Example fix

// before
new S3mini({ signRequest: '/api/s3/sign' }) // throws

// after
new S3mini({
  signRequest: async (req) =>
    (await fetch('/api/s3/sign', { method: 'POST', body: JSON.stringify(req) })).json(),
})
Defensive patterns

Strategy: type-guard

Validate before calling

if ('signRequest' in cfg && typeof cfg.signRequest !== 'function') throw new TypeError('signRequest must be a function')

Type guard

const isSignRequestFn = (f: unknown): f is IT.SignRequestFn => typeof f === 'function'

Prevention

When it happens

Trigger: new S3mini({ signRequest: '/api/s3/sign' }) (passing a URL string instead of a function), or signRequest: await getSigner() where the promise already resolved to a non-function, or signRequest: mySigner() invoking instead of referencing the callback.

Common situations: Confusing the presign endpoint URL with the callback; passing an object like {url: ...} from a config file; accidentally invoking the function during wiring; JSON configs that can't hold functions.

Related errors


AI-assisted analysis of transloadit/uppy@5d4dedd02a (2026-08-28). Data as JSON: /api/errors/932b13eb99c97870. Report an issue: GitHub.