{"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":226,"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":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/proxy/providers/bedrock/signing.go#L208-L244","documentation":"parseAWSCredentials decodes the accessKeyId:secretAccessKey[:sessionToken] form and fails closed on an empty input: an empty x-cave-upstream-key can never produce valid SigV4 credentials, so it is rejected instead of silently sending an unsigned request.","triggerScenarios":"parseAWSCredentials is called with raw == \"\" — either directly from SanitizeAndMapHeaders when building SigV4 credentials, or from credentialAuthKind's inference path where the AuthKind check itself calls parseAWSCredentials on an empty key.","commonSituations":"AWS access keys env var or x-cave-upstream-key header unset/empty; secret store returning an empty string for a missing secret; whitespace value that was trimmed to empty before the call.","solutions":["Provide the full accessKeyId:secretAccessKey[:sessionToken] string in x-cave-upstream-key","Check the env var / secret store actually contains the AWS keys and that the correct variable name is wired to the Bedrock provider","If you meant to use a Bedrock API key instead of IAM, ensure the key is non-empty (it will then be inferred as bedrock_api_key)"],"exampleFix":"// before\n// x-cave-upstream-key: (empty)\n// after\n// x-cave-upstream-key: AKIAIOSFODNN7EXAMPLE:wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY","handlingStrategy":"validation","validationCode":"raw := strings.TrimSpace(cfg.BedrockUpstreamKey)\nif raw == \"\" { return errors.New(\"x-cave-upstream-key is required for Bedrock IAM auth\") }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check required credentials at provider startup, not per-request","Wire secret-store values with tests asserting non-empty","Trim env values before assignment"],"tags":["bedrock","aws","credentials","sigv4"],"backgroundTag":"missing-credentials","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}