alibaba/open-code-review · error

bedrock could not authenticate: AWS credentials are expired

Error message

bedrock could not authenticate: AWS credentials are expired or unavailable (%s): %w
  run `aws sso login%s`, or refresh whichever credential source this profile uses

What it means

explainError (internal/llm/client.go:1124) matches specific AWS credential-failure codes — ExpiredToken, ExpiredTokenException, SSOProviderInvalidToken, InvalidGrantException, NoCredentialProviders, 'failed to refresh cached credentials' — and rewrites them as 'bedrock could not authenticate: AWS credentials are expired or unavailable'. Only exact credential codes match so unrelated 'expired' errors (e.g. TLS cert expiry) are not mislabeled.

Source

Thrown at internal/llm/client.go:1124

			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
	// policy change, not a console toggle.
	case strings.Contains(msg, "AccessDenied"),
		strings.Contains(msg, "not authorized to invoke this API operation"):
		return fmt.Errorf("bedrock denied access to model %q (%s): %w\n"+
			"  credentials resolved, so this is an authorization gap: the identity needs bedrock:InvokeModel on this model in this region, and the account needs model access enabled for it", model, where, err)
	}
	// Everything else — ValidationException on max_tokens, a network reset, a
	// throttle — keeps the service's own wording. Guessing at a cause here would
	// send people after the wrong problem, which is the failure this function
	// exists to prevent.
	return fmt.Errorf("bedrock request failed (%s): %w", where, err)
}

func listProfilesRegionArg(region string) string {
	if region == "" {

View on GitHub (pinned to 5cf97d0d15)

Solutions

  1. Run `aws sso login` (append `--profile <profile>` if one is active) to mint fresh SSO credentials
  2. Re-export fresh AWS_ACCESS_KEY_ID/SECRET/SESSION_TOKEN if using static temp credentials
  3. Run `aws sts get-caller-identity` to confirm credentials now resolve and are valid
  4. If a credential_process supplies tokens, extend its refresh or re-run it

Example fix

// before
# SSO session from yesterday
ocr review ...  # ExpiredToken
// after
aws sso login --profile work
ocr review ...  # succeeds
Defensive patterns

Strategy: retry

Validate before calling

if err := exec.Command("aws", "sts", "get-caller-identity").Run(); err != nil {
    exec.Command("aws", "sso", "login").Run()
}

Try / catch

_, err := cl.Call(ctx, messages)
if err != nil && strings.Contains(err.Error(), "could not authenticate") {
    if err2 := exec.Command("aws", "sso", "login").Run(); err2 == nil {
        return retryCall(ctx)
    }
    return err
}

Prevention

When it happens

Trigger: A bedrock-runtime InvokeModel call fails at the auth layer because cached SSO credentials expired (default 12h), an assume-role session token timed out, the credential-process returned an expired token, or no provider could produce credentials at request time.

Common situations: Next-day use of a machine whose `aws sso login` from yesterday lapsed; long-running CI job outliving temporary credentials; IAM Identity Center session revoked; STS session from env vars hit its 1-12h limit.

Understand the failure class

Related errors


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