{"record":{"id":"ef834fdf3cdaf368","repo":"alibaba/open-code-review","slug":"bedrock-rejected-the-token-in-aws-bearer-token-bed","errorCode":null,"errorMessage":"bedrock rejected the token in AWS_BEARER_TOKEN_BEDROCK (%s): %w\n  unset that variable to sign requests with SigV4 instead","messagePattern":"bedrock rejected the token in AWS_BEARER_TOKEN_BEDROCK \\((.+?)\\): %w\n  unset that variable to sign requests with SigV4 instead","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/llm/client.go","lineNumber":1106,"sourceCode":"// model that is merely absent from the region reads as a malformed identifier.\n// Non-Bedrock clients are unaffected — the error is returned untouched.\nfunc (c *AnthropicClient) explainError(model string, err error) error {\n\tif err == nil || !c.bedrock {\n\t\treturn err\n\t}\n\tmsg := err.Error()\n\twhere := c.bedrockWhere()\n\n\t// Order matters here, and the two AccessDenied shapes are why: Bedrock\n\t// answers both \"your IAM policy forbids this\" and \"this account has not\n\t// enabled the model\" with AccessDeniedException, and the fixes have nothing\n\t// in common. The specific wording is matched before the generic code.\n\tswitch {\n\t// First: the bearer-token path produces this even when credentials are\n\t// otherwise valid, so a later \"denied\" branch would mislabel it.\n\tcase strings.Contains(msg, \"Invalid API Key format\"):\n\t\tif os.Getenv(\"AWS_BEARER_TOKEN_BEDROCK\") != \"\" {\n\t\t\treturn fmt.Errorf(\"bedrock rejected the token in AWS_BEARER_TOKEN_BEDROCK (%s): %w\\n\"+\n\t\t\t\t\"  unset that variable to sign requests with SigV4 instead\", where, err)\n\t\t}\n\t\treturn fmt.Errorf(\"bedrock rejected an API-key header rather than a signature (%s): %w\\n\"+\n\t\t\t\"  no api_key applies to bedrock; this means a bearer token reached the request, not that a key is missing\", where, err)\n\tcase strings.Contains(msg, \"don't have access to the model\"):\n\t\treturn fmt.Errorf(\"bedrock has no access enabled for model %q (%s): %w\\n\"+\n\t\t\t\"  model access is granted per account and per region in the Bedrock console; an IAM policy alone does not enable it\", model, where, err)\n\tcase strings.Contains(msg, \"model identifier is invalid\"),\n\t\tstrings.Contains(msg, \"inference profile\") && strings.Contains(msg, \"not found\"):\n\t\treturn fmt.Errorf(\"bedrock rejected model %q (%s): %w\\n\"+\n\t\t\t\"  run `aws bedrock list-inference-profiles%s` to see what this account offers — IDs are account- and region-scoped, and a version suffix such as -v1:0 is invalid for the newer families\",\n\t\t\tmodel, where, err, listProfilesRegionArg(c.awsRegion))\n\t// Specific credential codes only. A bare \"expired\" would also claim an\n\t// expired TLS certificate is an SSO problem.\n\tcase strings.Contains(msg, \"ExpiredToken\"), strings.Contains(msg, \"ExpiredTokenException\"),\n\t\tstrings.Contains(msg, \"SSOProviderInvalidToken\"), strings.Contains(msg, \"InvalidGrantException\"),\n\t\tstrings.Contains(msg, \"NoCredentialProviders\"), strings.Contains(msg, \"failed to refresh cached credentials\"):\n\t\treturn fmt.Errorf(\"bedrock could not authenticate: AWS credentials are expired or unavailable (%s): %w\\n\"+","sourceCodeStart":1088,"sourceCodeEnd":1124,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/internal/llm/client.go#L1088-L1124","documentation":"explainError (internal/llm/client.go:1106) rewrites Bedrock API failures into actionable text. Bedrock rejects a malformed bearer token with an 'Invalid API Key format' complaint; when AWS_BEARER_TOKEN_BEDROCK is set, this branch matches that wording and blames the env var specifically, telling the user to unset it so requests fall back to SigV4 signing. It exists because the service's own wording misleadingly suggests an API key is missing when actually the provided token is bad.","triggerScenarios":"AWS_BEARER_TOKEN_BEDROCK contains a truncated, whitespace-mangled, expired, or non-Bedrock token and a bedrock-runtime InvokeModel call is made; the service answers 'Invalid API Key format' and explainError rewrites it with this message.","commonSituations":"User pasted an API key meant for the Anthropic API into AWS_BEARER_TOKEN_BEDROCK; token exported by a stale shell profile after rotating; copy-paste dropped characters; Bedrock API keys feature region mismatches.","solutions":["Unset AWS_BEARER_TOKEN_BEDROCK (unset AWS_BEARER_TOKEN_BEDROCK) so requests use SigV4 signing with normal credentials","If a bearer token is required, re-copy a fresh Bedrock API key from the AWS console without truncation","Verify the token is a Bedrock key, not an Anthropic or OpenAI key","Re-source your shell profile after fixing so the stale export disappears"],"exampleFix":"// before\nexport AWS_BEARER_TOKEN_BEDROCK=sk-ant-api03-xxxx  # wrong provider's key\n// after\nunset AWS_BEARER_TOKEN_BEDROCK\nexport AWS_PROFILE=work && aws sso login --profile work  # SigV4 path","handlingStrategy":"validation","validationCode":"if tok := os.Getenv(\"AWS_BEARER_TOKEN_BEDROCK\"); tok != \"\" && !strings.HasPrefix(tok, \"bedrock-api-key\") {\n    return fmt.Errorf(\"AWS_BEARER_TOKEN_BEDROCK does not look like a Bedrock key; unset it to use SigV4\")\n}","typeGuard":null,"tryCatchPattern":"_, err := cl.Call(ctx, messages)\nif err != nil && strings.Contains(err.Error(), \"AWS_BEARER_TOKEN_BEDROCK\") {\n    os.Unsetenv(\"AWS_BEARER_TOKEN_BEDROCK\")\n    return retryWithSigV4(ctx)\n}","preventionTips":["Do not export AWS_BEARER_TOKEN_BEDROCK unless you specifically want bearer-token auth","Never paste non-AWS (Anthropic/OpenAI) keys into AWS_* variables","Clean shell rc files of stale token exports after rotation","Prefer SigV4 via standard credentials for interactive use"],"tags":["aws","bedrock","bearer-token","authentication"],"backgroundTag":"invalid-bearer-token","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}