alibaba/open-code-review · error

bedrock rejected an API-key header rather than a signature (

Error message

bedrock rejected an API-key header rather than a signature (%s): %w
  no api_key applies to bedrock; this means a bearer token reached the request, not that a key is missing

What it means

The fallback half of the 'Invalid API Key format' branch in explainError (internal/llm/client.go:1109). Bedrock answered with an API-key-format rejection, but AWS_BEARER_TOKEN_BEDROCK is NOT set — so a bearer token still reached the request from somewhere else (SDK-managed token, BearerToken provider in the loaded config). The message clarifies that no api_key configuration applies to Bedrock and a token leaked into the request rather than a key being missing.

Source

Thrown at internal/llm/client.go:1109

	if err == nil || !c.bedrock {
		return err
	}
	msg := err.Error()
	where := c.bedrockWhere()

	// Order matters here, and the two AccessDenied shapes are why: Bedrock
	// answers both "your IAM policy forbids this" and "this account has not
	// enabled the model" with AccessDeniedException, and the fixes have nothing
	// in common. The specific wording is matched before the generic code.
	switch {
	// First: the bearer-token path produces this even when credentials are
	// otherwise valid, so a later "denied" branch would mislabel it.
	case strings.Contains(msg, "Invalid API Key format"):
		if os.Getenv("AWS_BEARER_TOKEN_BEDROCK") != "" {
			return fmt.Errorf("bedrock rejected the token in AWS_BEARER_TOKEN_BEDROCK (%s): %w\n"+
				"  unset that variable to sign requests with SigV4 instead", where, err)
		}
		return fmt.Errorf("bedrock rejected an API-key header rather than a signature (%s): %w\n"+
			"  no api_key applies to bedrock; this means a bearer token reached the request, not that a key is missing", where, err)
	case strings.Contains(msg, "don't have access to the model"):
		return fmt.Errorf("bedrock has no access enabled for model %q (%s): %w\n"+
			"  model access is granted per account and per region in the Bedrock console; an IAM policy alone does not enable it", model, where, err)
	case strings.Contains(msg, "model identifier is invalid"),
		strings.Contains(msg, "inference profile") && strings.Contains(msg, "not found"):
		return fmt.Errorf("bedrock rejected model %q (%s): %w\n"+
			"  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",
			model, where, err, listProfilesRegionArg(c.awsRegion))
	// Specific credential codes only. A bare "expired" would also claim an
	// expired TLS certificate is an SSO problem.
	case strings.Contains(msg, "ExpiredToken"), strings.Contains(msg, "ExpiredTokenException"),
		strings.Contains(msg, "SSOProviderInvalidToken"), strings.Contains(msg, "InvalidGrantException"),
		strings.Contains(msg, "NoCredentialProviders"), strings.Contains(msg, "failed to refresh cached credentials"):
		return fmt.Errorf("bedrock could not authenticate: AWS credentials are expired or unavailable (%s): %w\n"+
			"  run `aws sso login%s`, or refresh whichever credential source this profile uses", where, err, ssoLoginProfileArg(c.awsProfile))
	// "not authorized to invoke this API operation" is IAM's own wording, so it
	// belongs here rather than in the model-access branch above: the fix is a

View on GitHub (pinned to 5cf97d0d15)

Solutions

  1. Search the environment for any AWS_BEARER_TOKEN* or token variables: env | grep -i bearer, and unset them
  2. Check ~/.aws/config for bearer_token or api-key style settings and remove them
  3. Bypass or reconfigure any proxy that injects Authorization headers toward bedrock-runtime
  4. Run with AWS_SDK_LOAD_CONFIG inspection / debug logging to see which credential provider supplied the token

Example fix

// before
env | grep -i bearer   # AWS_BEARER_TOKEN_BEDROCK_API_KEY=abc found (different name, still honored)
// after
unset AWS_BEARER_TOKEN_BEDROCK_API_KEY
# requests now sign with SigV4
Defensive patterns

Strategy: type-guard

Validate before calling

for _, e := range os.Environ() {
    if strings.HasPrefix(e, "AWS_BEARER_TOKEN") {
        return fmt.Errorf("unexpected %s set — unset it so SigV4 signing is used", e)
    }
}

Type guard

func bearerTokenLeaked(env []string) (string, bool) {
    for _, kv := range env {
        if strings.HasPrefix(kv, "AWS_BEARER_TOKEN") {
            return kv, true
        }
    }
    return "", false
}

Try / catch

_, err := cl.Call(ctx, messages)
if err != nil && strings.Contains(err.Error(), "rejected an API-key header") {
    env, ok := bearerTokenLeaked(os.Environ())
    if ok { log.Printf("token source: %s — unset it", env) }
    return err
}

Prevention

When it happens

Trigger: A Bedrock InvokeModel call gets 'Invalid API Key format' while the env var is unset: an SDK BearerToken provider (e.g. from a shared config or another AWS_BEARER_TOKEN_* variable) attached a token to the request, or an intermediate proxy injected an Authorization header the service read as an API key.

Common situations: A wrapper script or IDE terminal exported a bearer token under a different name that the AWS SDK still honors; AWS SDK experimental bearer-token config keys enabled in ~/.aws/config; corporate proxy adding an Authorization header.

Related errors


AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02). Data as JSON: /api/errors/6c8b8f262f056bad. Report an issue: GitHub.