In AWS SDK v3, client credentials go in a nested credentials object: const client = new S3Client({ region: "us-east-1", credentials: { accessKeyId: "...", secretAccessKey: "...", sessionToken - "...", // needed for STS/assumed-role creds }, }); The v2 habit of AWS.config.update({ accessKeyId, secretAccessKey }) as flat keys does not transfer. In v3 every client constructor takes the same shape: { region, credentials: {...} }. "Credential is missing" on a client you just configured almost always means the keys are at the wrong nesting level, or you passed an AWS.Credentials-shaped object where the plain { accessKeyId, secretAccessKey } form was expected. When using STS session credentials, do not forget sessionToken or calls fail with auth errors that look like bad keys.

Context: Stack Overflow #62612082 (accepted answer, 6 votes): a developer passing STS credentials to the v3 S3 client got "Credential is missing" because in v3 the credentials must be nested inside a credentials object on the client config, not passed as flat keys like v2's AWS.config.update({ accessKeyId, secretAccessKey }). The verified fix: new S3Client({ region, credentials: { accessKeyId, secretAccessKey, sessionToken } }). The constructor argument is literally named credentials.