transloadit/uppy · error · TypeError

s3Endpoint must be a string

Error message

s3Endpoint must be a string

What it means

Each Companion provider class exposes an oauthProvider string identifying the grant provider (e.g. 'google', 'dropbox'). If the provider class for the requested provider has a null/empty oauthProvider, Companion cannot build the grant authorize URL and returns 400.

Source

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

    this.#setResumableUploadsCapability(true)
    this.#queue.clear()
  }

  // --------------------------------------------------------------------------
  // S3 Client Initialization
  // --------------------------------------------------------------------------

  #initS3Client(): void {
    if ('companionEndpoint' in this.opts) {
      if (typeof this.opts.companionEndpoint !== 'string') {
        throw new TypeError('companionEndpoint must be a string')
      }
      this.#s3Client = new S3Companion({
        companionEndpoint: this.opts.companionEndpoint,
      })
    } else if ('getCredentials' in this.opts) {
      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')
      }

View on GitHub (pinned to 5d4dedd02a)

Solutions

  1. If using a custom provider, set `static oauthProvider = 'mygrantprovider'` (matching the grant config key)
  2. Do not call /connect/:providerName for providers that are not OAuth-based
  3. Verify the provider class version matches the Companion version (API changes across upgrades)

Example fix

// before
class MyProvider extends Provider { /* missing oauthProvider */ }
// after
class MyProvider extends Provider {
  static oauthProvider = 'myprovider'
  // ...
}
Defensive patterns

Strategy: type-guard

Type guard

class MyProvider extends Provider {
  static oauthProvider = 'myprovider'
}
const hasOAuthProvider = (C: typeof Provider): C is typeof Provider & { oauthProvider: string } =>
  typeof (C as any).oauthProvider === 'string' && (C as any).oauthProvider.length > 0

Prevention

When it happens

Trigger: Using a custom provider class that forgets to set the oauthProvider static property; or a provider whose grant config does not map to an OAuth provider (some providers like local-disk or transloadit-style integrations do not use OAuth and should not go through /connect).

Common situations: Writing a custom provider and missing the static oauthProvider field; attempting to 'connect' to a non-OAuth provider via the OAuth connect endpoint.

Related errors


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