{"record":{"id":"544bdd7b4e657449","repo":"JuliusBrussee/caveman","slug":"bedrock-missing-aws-credentials-in-x-cave-upstrea","errorCode":null,"errorMessage":"bedrock: missing AWS credentials in x-cave-upstream-key","messagePattern":"bedrock: missing AWS credentials in x-cave-upstream-key","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/providers/bedrock/signing.go","lineNumber":170,"sourceCode":"\t\t// bearer. Every other opaque value is a Bedrock API key.\n\t\tif _, err := parseAWSCredentials(key); err == nil {\n\t\t\treturn \"aws_access_keys\", nil\n\t\t}\n\t\tif strings.HasPrefix(key, \"AKIA\") || strings.HasPrefix(key, \"ASIA\") {\n\t\t\treturn \"aws_access_keys\", nil\n\t\t}\n\t\treturn \"bedrock_api_key\", nil\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"bedrock: unsupported credential auth kind\")\n\t}\n}\n\n// parseAWSCredentials decodes the \"accessKeyId:secretAccessKey[:sessionToken]\"\n// form carried in x-cave-upstream-key into awssig.Credentials. It fails closed:\n// a missing access key or secret is an error, never an unsigned passthrough.\nfunc parseAWSCredentials(raw string) (awssig.Credentials, error) {\n\tif raw == \"\" {\n\t\treturn awssig.Credentials{}, fmt.Errorf(\"bedrock: missing AWS credentials in x-cave-upstream-key\")\n\t}\n\tparts := strings.SplitN(raw, \":\", 3)\n\tif len(parts) < 2 || parts[0] == \"\" || parts[1] == \"\" {\n\t\treturn awssig.Credentials{}, fmt.Errorf(\"bedrock: malformed AWS credentials (want accessKeyId:secretAccessKey[:sessionToken])\")\n\t}\n\tcreds := awssig.Credentials{AccessKeyID: parts[0], SecretAccessKey: parts[1]}\n\tif len(parts) == 3 {\n\t\tcreds.SessionToken = parts[2]\n\t}\n\treturn creds, nil\n}\n\n// copyIfPresent copies a header from src to dst when present (case-insensitive).\nfunc copyIfPresent(dst, src http.Header, name string) {\n\tif values := src.Values(name); len(values) > 0 {\n\t\tfor _, v := range values {\n\t\t\tdst.Add(name, v)\n\t\t}","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/proxy/providers/bedrock/signing.go#L152-L188","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\nexport CAVE_UPSTREAM_KEY=\"\"\n\n# after (IAM access keys, colon form)\nexport CAVE_UPSTREAM_KEY=\"AKIAIOSFODNN7EXAMPLE:wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\"","handlingStrategy":"validation","validationCode":"func hasIAMCredential(key string) bool {\n    return strings.TrimSpace(key) != \"\"\n}","typeGuard":null,"tryCatchPattern":"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.","preventionTips":["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."],"tags":["bedrock","authentication","credentials","aws"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}