JuliusBrussee/caveman · error
bedrock: missing AWS credentials in x-cave-upstream-key
Error message
bedrock: missing AWS credentials in x-cave-upstream-key
What it means
Thrown by parseAWSCredentials when the raw credential string is empty. The Bedrock adapter carries AWS IAM credentials in the x-cave-upstream-key header / stored connection value as "accessKeyId:secretAccessKey[:sessionToken]"; the parser fails closed so an empty value never becomes an unsigned passthrough or a request signed with zero-length keys.
Source
Thrown at proxy/providers/bedrock/signing.go:170
// bearer. Every other opaque value is a Bedrock API key.
if _, err := parseAWSCredentials(key); err == nil {
return "aws_access_keys", nil
}
if strings.HasPrefix(key, "AKIA") || strings.HasPrefix(key, "ASIA") {
return "aws_access_keys", nil
}
return "bedrock_api_key", nil
default:
return "", fmt.Errorf("bedrock: unsupported credential auth kind")
}
}
// parseAWSCredentials decodes the "accessKeyId:secretAccessKey[:sessionToken]"
// form carried in x-cave-upstream-key into awssig.Credentials. It fails closed:
// a missing access key or secret is an error, never an unsigned passthrough.
func parseAWSCredentials(raw string) (awssig.Credentials, error) {
if raw == "" {
return awssig.Credentials{}, fmt.Errorf("bedrock: missing AWS credentials in x-cave-upstream-key")
}
parts := strings.SplitN(raw, ":", 3)
if len(parts) < 2 || parts[0] == "" || parts[1] == "" {
return awssig.Credentials{}, fmt.Errorf("bedrock: malformed AWS credentials (want accessKeyId:secretAccessKey[:sessionToken])")
}
creds := awssig.Credentials{AccessKeyID: parts[0], SecretAccessKey: parts[1]}
if len(parts) == 3 {
creds.SessionToken = parts[2]
}
return creds, nil
}
// copyIfPresent copies a header from src to dst when present (case-insensitive).
func copyIfPresent(dst, src http.Header, name string) {
if values := src.Values(name); len(values) > 0 {
for _, v := range values {
dst.Add(name, v)
}View on GitHub (pinned to 27d5a3981a)
Solutions
- Supply the full colon-form credential: "AKIA...:secretKey" or "AKIA...:secretKey:sessionToken".
- Check the env var / stored connection that populates the key is actually set in the running environment (empty string vs unset).
- If the intent was a Bedrock API key rather than IAM, use AuthKind "bedrock_api_key" with the opaque key value.
Example fix
# before export CAVE_UPSTREAM_KEY="" # after (IAM access keys, colon form) export CAVE_UPSTREAM_KEY="AKIAIOSFODNN7EXAMPLE:wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
Defensive patterns
Strategy: validation
Validate before calling
func hasIAMCredential(key string) bool {
return strings.TrimSpace(key) != ""
} Try / catch
Treat this error as fatal for the request: return a credential configuration error to the caller and log the credential identifier (not the value). Do not fall back to unsigned requests.
Prevention
- Fail startup or connection-save when a Bedrock credential resolves to an empty key.
- Smoke-test the credential (e.g. a ListFoundationModels call) right after configuring it.
- Quote env values and use `set -u` / required-var checks in deploy scripts so empty secrets are caught at deploy time.
When it happens
Trigger: parseAWSCredentials is called with "" — i.e. the signing path selected IAM (aws_access_keys) but the credential Key was blank, or a caller explicitly passed an empty x-cave-upstream-key value into the parser.
Common situations: A stored Bedrock connection whose secret field was never filled in; an env var feeding the key (e.g. CAVE upstream key env) is unset so the value resolves to empty; a credential object constructed with AuthKind "aws_access_keys" but Key left blank.
Related errors
- bedrock: malformed AWS credentials (want accessKeyId:secretA
- bedrock: unsupported credential auth kind
- cache-replay: Bedrock bearer token or AWS access credentials
- bedrock base url invalid: %w
- bedrock configured endpoint kind %q does not allow request k
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/544bdd7b4e657449.
Report an issue: GitHub.