transloadit/uppy · error · Error

Missing S3 object key for uploading part

Error message

Missing S3 object key for uploading part

What it means

The callback completed token exchange but req.companion.providerClass is falsy — the provider named in the URL is not registered/known to this Companion instance at this stage of the flow. Companion refuses to continue with 400 rather than crash.

Solutions

  1. Confirm the provider is fully configured in companionOptions.providers plus its key/secret
  2. Check for typos in the providerName in both the frontend Uppy config and the callback URL
  3. Restart Companion after adding provider configuration
  4. If using a custom provider, verify it is properly registered in the providers map

Example fix

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

Strategy: validation

Validate before calling

const configured = ['drive', 'dropbox', 'box'] // mirror companionOptions.providers
if (!configured.includes(providerName)) throw new Error(`provider ${providerName} not enabled`)

Type guard

const isConfiguredProvider = (p: string): boolean =>
  configuredProviders.includes(p)

Prevention

When it happens

Trigger: providerName in the callback URL does not match any enabled provider (e.g. /connect/unknownprov/callback), or the provider was configured via grant but its Companion provider class was not loaded/enabled (missing key/secret so it was filtered out).

Common situations: Enabling a provider in grant config without providing its Companion options (key/secret); a typo in the custom provider name; upgrading Companion where a provider was renamed or moved behind a flag.

Related errors


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

Appendix: source

Thrown at packages/@uppy/aws-s3/src/S3Uploader.ts:312

    this.#options.uppy.setFileState(this.#options.file.id, {
      s3Multipart: { uploadId, key },
    })

    await this.#uploadRemainingParts(signal)
  }

  async #uploadRemainingParts(signal: AbortSignal): Promise<void> {
    for (let i = 0; i < this.#chunks.length; i++) {
      signal.throwIfAborted()
      if (this.#chunkState[i].etag) continue // already uploaded

      const chunk = this.#chunks[i]
      const partNumber = i + 1
      const chunkData = this.#data.slice(chunk.start, chunk.end)
      const chunkIndex = i // Capture for closure (cannot use for-loop variable i directly in a closure)

      if (this.#key == null) {
        throw new Error('Missing S3 object key for uploading part')
      }
      const { etag } = await this.#options.s3Client.uploadPart({
        key: this.#key,
        uploadId: this.#uploadId!,
        data: chunkData,
        partNumber,
        onProgress: (bytesUploaded: number) => {
          this.#chunkState[chunkIndex].uploaded = bytesUploaded
          this.#onProgress()
        },
        signal,
      })

      // after part finished uploading, update chunk state
      this.#chunkState[i].uploaded = chunk.size
      this.#chunkState[i].etag = etag
      this.#onProgress()

View on GitHub (pinned to 5d4dedd02a)