{"record":{"id":"d12e1027d10e14d2","repo":"JuliusBrussee/caveman","slug":"kms-decode-envelope-w","errorCode":null,"errorMessage":"kms: decode envelope: %w","messagePattern":"kms: decode envelope: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/platform/kms/kms.go","lineNumber":231,"sourceCode":"\tclient, err := FromPayloadEnvironment()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn client.Decrypt(ctx, blob)\n}\n\n// Decrypt unwraps versioned KMS envelope. Metadata can choose only validated\n// key identity under configured provider; it can never choose host or token.\nfunc (c *Client) Decrypt(ctx context.Context, blob []byte) ([]byte, error) {\n\tif !IsEnvelope(blob) {\n\t\treturn nil, errors.New(\"kms: unknown envelope format\")\n\t}\n\tif len(blob) > maxEnvelopeBytes {\n\t\treturn nil, errors.New(\"kms: envelope exceeds size limit\")\n\t}\n\tvar envelope Envelope\n\tif err := json.Unmarshal(blob[len(prefix):], &envelope); err != nil {\n\t\treturn nil, fmt.Errorf(\"kms: decode envelope: %w\", err)\n\t}\n\tif envelope.Provider != c.provider {\n\t\treturn nil, errors.New(\"kms: envelope provider does not match configured provider\")\n\t}\n\tif err := validateLocation(envelope.Region, envelope.KeyID); err != nil {\n\t\treturn nil, err\n\t}\n\tif envelope.Region != c.region {\n\t\treturn nil, errors.New(\"kms: envelope region is not approved\")\n\t}\n\tif _, ok := c.decryptKeyIDs[envelope.KeyID]; !ok {\n\t\treturn nil, errors.New(\"kms: envelope key ID is not approved\")\n\t}\n\tif strings.TrimSpace(envelope.Ciphertext) == \"\" {\n\t\treturn nil, errors.New(\"kms: envelope ciphertext is empty\")\n\t}\n\tvar response struct {\n\t\tKeyID     string `json:\"key_id\"`","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/shared/platform/kms/kms.go#L213-L249","documentation":"Decrypt unmarshals the JSON that follows the envelope prefix in the blob; a json.Unmarshal failure is wrapped as \"kms: decode envelope: %w\". It indicates the ciphertext blob is not a valid JSON envelope after prefix stripping — typically corruption, truncation, or a blob produced by a different tool/version.","triggerScenarios":"Calling Decrypt with a blob whose post-prefix bytes are not valid JSON: truncated storage, base64/text encoding mangled the bytes, wrong prefix handling, or an envelope written by another KMS format.","commonSituations":"Storing envelopes in a DB column that strips padding or re-encodes; copy-pasting an envelope through a medium that alters characters; reading a partial write after a crash; mixing envelope formats across library versions.","solutions":["Verify the blob starts with the expected prefix and the remainder is valid JSON (json.Valid on the slice after the prefix).","Re-encrypt the data — the original envelope is unrecoverable if the bytes are truly corrupted.","Check the storage/transport path (encoding, column charset, file truncation) that delivered the blob.","Confirm the blob was produced by this library's Encrypt and not another tool."],"exampleFix":"// before\ndec, err := kms.Decrypt(ctx, blob) // kms: decode envelope: invalid character...\n// after\nif !bytes.HasPrefix(blob, prefix) || !json.Valid(blob[len(prefix):]) {\n    return fmt.Errorf(\"malformed kms envelope (len=%d)\", len(blob))\n}\ndec, err := kms.Decrypt(ctx, blob)","handlingStrategy":"validation","validationCode":"if !bytes.HasPrefix(blob, kmsPrefix) || len(blob) <= len(kmsPrefix) || !json.Valid(blob[len(kmsPrefix):]) {\n    return errors.New(\"blob is not a valid kms envelope\")\n}","typeGuard":"func isKMSEnvelope(blob []byte) bool {\n    return bytes.HasPrefix(blob, prefix) && json.Valid(blob[len(prefix):])\n}","tryCatchPattern":"dec, err := kms.Decrypt(ctx, blob)\nif err != nil {\n    if strings.Contains(err.Error(), \"decode envelope\") {\n        return fmt.Errorf(\"corrupt or foreign envelope (len=%d): %w\", len(blob), err)\n    }\n    return err\n}","preventionTips":["Store envelopes in binary-safe columns (bytea/blob), not text with charset transforms.","Never round-trip envelopes through encodings that alter bytes (lossy base64, JSON string escapes).","Version-stamp envelopes and validate format before Decrypt.","Fail fast on truncated reads (compare stored length vs read length)."],"tags":["go","kms","envelope","json","decode"],"backgroundTag":"json-decode-failed","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"}