transloadit/uppy · error · TypeError

signRequest must be a function

Error message

signRequest must be a function

What it means

The get controller requires an initialized provider instance on req.companion (set by middleware once the user is authenticated). If provider is falsy the request cannot proceed and 400 is returned before attempting size/stream operations.

Source

Thrown at packages/@uppy/aws-s3/src/index.ts:208

      if (typeof this.opts.s3Endpoint !== 'string') {
        throw new TypeError('s3Endpoint must be a string')
      }
      if (typeof this.opts.getCredentials !== 'function') {
        throw new TypeError('getCredentials must be a function')
      }
      if (this.opts.region != null && typeof this.opts.region !== 'string') {
        throw new TypeError('region must be a string')
      }

      // Mode: Temporary credentials (client-side signing)
      this.#s3Client = new S3mini({
        endpoint: this.opts.s3Endpoint,
        getCredentials: this.opts.getCredentials,
        region: this.opts.region,
      })
    } else if ('signRequest' in this.opts) {
      if (typeof this.opts.signRequest !== 'function') {
        throw new TypeError('signRequest must be a function')
      }
      // Mode: Custom signing function
      this.#s3Client = new S3mini({
        signRequest: this.opts.signRequest,
      })
    } else {
      throw new TypeError(
        'One of options `companionEndpoint`, `signRequest`, or `getCredentials` is required',
      )
    }
  }

  // --------------------------------------------------------------------------
  // Upload Entry Point
  // --------------------------------------------------------------------------

  #upload = async (fileIDs: string[]): Promise<void> => {
    if (fileIDs.length === 0) return

View on GitHub (pinned to 5d4dedd02a)

Solutions

  1. Verify the provider is in companionOptions.providers with valid key/secret
  2. Ensure the client sends a valid, unexpired token for the provider session
  3. Align provider names (case-sensitive) between Uppy's frontend options and Companion
  4. Check middleware logs to see why the provider instance was not created

Example fix

// before
companion({ providers: ['drive'] }) // client requests box
// after
companion({ providers: ['drive', 'box'], providerOptions: { box: { key: '...', secret: '...' } } })
Defensive patterns

Strategy: validation

Validate before calling

if (!enabledProviders.includes(providerName)) {
  throw new Error(`provider ${providerName} not available`)
}

Type guard

const isProviderAvailable = (p: string): boolean =>
  enabledProviders.includes(p) && Boolean(providerOptions[p]?.key)

Try / catch

try {
  await providerClient.get(file)
} catch (e) {
  if (e.status === 400) return reAuthenticate() // session/provider missing
  throw e
}

Prevention

When it happens

Trigger: Requesting /get for a provider that is not enabled/configured on this Companion, or hitting the endpoint without a valid provider session so the middleware never attached the provider instance.

Common situations: Frontend configured with a provider the backend does not have key/secret for; expired/invalid uppyAuthToken so provider instantiation was skipped; mismatched provider names between frontend and Companion config.

Related errors


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