{"record":{"id":"beb64bf2c6c0dd71","repo":"JuliusBrussee/caveman","slug":"kms-probe-decrypt-w","errorCode":null,"errorMessage":"kms: probe decrypt: %w","messagePattern":"kms: probe decrypt: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/platform/kms/kms.go","lineNumber":328,"sourceCode":"\tif err != nil {\n\t\treturn err\n\t}\n\treturn client.Probe(ctx)\n}\n\n// Probe verifies live key access without persisting tenant data.\nfunc (c *Client) Probe(ctx context.Context) error {\n\tplaintext := make([]byte, 32)\n\tif _, err := rand.Read(plaintext); err != nil {\n\t\treturn fmt.Errorf(\"kms: generate probe: %w\", err)\n\t}\n\tenvelope, err := c.Encrypt(ctx, plaintext)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"kms: probe encrypt: %w\", err)\n\t}\n\tdecrypted, err := c.Decrypt(ctx, envelope)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"kms: probe decrypt: %w\", err)\n\t}\n\tif !bytes.Equal(decrypted, plaintext) {\n\t\treturn errors.New(\"kms: probe plaintext mismatch\")\n\t}\n\treturn nil\n}\n\nfunc validateLocation(region, keyID string) error {\n\tif !regionPattern.MatchString(region) {\n\t\treturn errors.New(\"kms: invalid Scaleway region\")\n\t}\n\tif !keyIDPattern.MatchString(keyID) {\n\t\treturn errors.New(\"kms: invalid Scaleway key ID\")\n\t}\n\treturn nil\n}\n\nfunc (c *Client) call(ctx context.Context, region, keyID, operation string, input, output any) error {","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/shared/platform/kms/kms.go#L310-L346","documentation":"The second stage of Probe: encryption succeeded, but Decrypt of the just-produced envelope failed, wrapped as 'kms: probe decrypt: %w'. Because the envelope was generated by the same client moments earlier, config mismatches (provider/region/keyID) are unlikely; realistic causes are an API-side decrypt failure, HTTP error on the decrypt call, or an invalid decrypt response payload.","triggerScenarios":"Scaleway key policy allowing encrypt but not decrypt on the token's service account; transient API failure between the two calls; decrypt response missing/blank plaintext causing 'invalid decrypt response'; envelope size or base64 issues never occur here since Encrypt just produced it.","commonSituations":"Least-privilege IAM policies granting encrypt-only; intermittent API errors during startup checks; API version change altering the decrypt response shape caught by strict response validation.","solutions":["Check the wrapped error for the specific stage (HTTP status vs response validation)","Review the key's IAM policy: the calling token needs both encrypt and decrypt permissions","Retry the probe once — a transient API error between the two calls is plausible","If response validation fails consistently, verify the package version matches the current key-manager API"],"exampleFix":"// before\n// service-account policy: { \"effect\": \"allow\", \"action\": \"kms_encrypt\" }\n\n// after\n// service-account policy:\n// { \"effect\": \"allow\", \"action\": [\"kms_encrypt\", \"kms_decrypt\"] }","handlingStrategy":"retry","validationCode":"if err := client.Probe(ctx); err != nil { /* distinguish decrypt-stage failure: likely IAM or transient */ }","typeGuard":null,"tryCatchPattern":"err := client.Probe(ctx)\nfor attempt := 0; err != nil && strings.Contains(err.Error(), \"probe decrypt\") && attempt < 2; attempt++ {\n\ttime.Sleep(200 * time.Millisecond)\n\terr = client.Probe(ctx)\n}","preventionTips":["Grant the calling token both encrypt and decrypt permissions on the key","Retry the probe once before declaring the KMS unhealthy","Include probe-stage in error reporting to speed up IAM diagnosis"],"tags":["go","kms","probe","iam"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}