{"record":{"id":"1ebec0f99cd1a9be","repo":"transloadit/uppy","slug":"getcredentials-must-be-a-function","errorCode":null,"errorMessage":"getCredentials must be a function","messagePattern":"getCredentials must be a function","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"warning","filePath":"packages/@uppy/aws-s3/src/index.ts","lineNumber":194,"sourceCode":"\n  // --------------------------------------------------------------------------\n  // S3 Client Initialization\n  // --------------------------------------------------------------------------\n\n  #initS3Client(): void {\n    if ('companionEndpoint' in this.opts) {\n      if (typeof this.opts.companionEndpoint !== 'string') {\n        throw new TypeError('companionEndpoint must be a string')\n      }\n      this.#s3Client = new S3Companion({\n        companionEndpoint: this.opts.companionEndpoint,\n      })\n    } else if ('getCredentials' in this.opts) {\n      if (typeof this.opts.s3Endpoint !== 'string') {\n        throw new TypeError('s3Endpoint must be a string')\n      }\n      if (typeof this.opts.getCredentials !== 'function') {\n        throw new TypeError('getCredentials must be a function')\n      }\n      if (this.opts.region != null && typeof this.opts.region !== 'string') {\n        throw new TypeError('region must be a string')\n      }\n\n      // Mode: Temporary credentials (client-side signing)\n      this.#s3Client = new S3mini({\n        endpoint: this.opts.s3Endpoint,\n        getCredentials: this.opts.getCredentials,\n        region: this.opts.region,\n      })\n    } else if ('signRequest' in this.opts) {\n      if (typeof this.opts.signRequest !== 'function') {\n        throw new TypeError('signRequest must be a function')\n      }\n      // Mode: Custom signing function\n      this.#s3Client = new S3mini({\n        signRequest: this.opts.signRequest,","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/transloadit/uppy/blob/5d4dedd02a1ac0ae022c75c54aca76558f88e256/packages/@uppy/aws-s3/src/index.ts#L176-L212","documentation":"The deauth-callback endpoint (called by the providers themselves, not Uppy clients, e.g. Dropbox or OneDrive revocation notifications) requires an initialized provider instance on req.companion. If provider is falsy the request is rejected with 400 because status-code semantics for this endpoint are provider-specific.","triggerScenarios":"POSTing a deauthorization webhook to a Companion instance where the named provider is not configured/enabled, or where the providerName does not resolve to an instantiated provider.","commonSituations":"The provider's developer app still has the webhook URL registered but Companion was reconfigured to drop that provider; pointing the provider webhook at the wrong Companion deployment; providerName typo in the webhook registration.","solutions":["Ensure the provider is enabled and has key/secret configured in Companion","Update or remove the webhook/deauthorization callback URL registered in the provider's developer console so it targets the correct deployment/provider route","Verify the deployment's provider list matches what the provider's app expects"],"exampleFix":"// before: webhook targets a Companion without OneDrive configured\n// after\ncompanion({ providers: ['onedrive'], providerOptions: { onedrive: { key: '...', secret: '...' } } })","handlingStrategy":"validation","validationCode":"// before registering the webhook in the provider's console, check Companion\nconst res = await fetch(`${companionUrl}/${provider}/deauth-callback`, { method: 'POST' })\nif (res.status === 400) console.error('provider not enabled for deauth')","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep provider developer-console webhooks in sync with Companion's enabled providers","Alert on repeated 400s from deauth-callback so stale webhooks get cleaned up"],"tags":["companion","webhook","deauthorization","http-400"],"backgroundTag":"provider-not-configured","analyzedSha":"5d4dedd02a1ac0ae022c75c54aca76558f88e256","analyzedAt":"2026-08-28T12:18:41.267Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}