{"record":{"id":"2caf46f99d3093a6","repo":"knadh/listmonk","slug":"webhook-key-is-not-configured-2caf46","errorCode":null,"errorMessage":"webhook key is not configured","messagePattern":"webhook key is not configured","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/bounce/webhooks/lettermint.go","lineNumber":47,"sourceCode":"\t\tMetadata json.RawMessage `json:\"metadata\"`\n\t\tTag      string          `json:\"tag\"`\n\t} `json:\"data\"`\n}\n\n// Lettermint handles bounce webhook notifications from Lettermint.\ntype Lettermint struct {\n\thmacKey []byte\n}\n\n// NewLettermint returns a new Lettermint webhook handler.\nfunc NewLettermint(key []byte) *Lettermint {\n\treturn &Lettermint{hmacKey: key}\n}\n\n// ProcessBounce processes an incoming Lettermint webhook payload and returns a bounce object.\nfunc (l *Lettermint) ProcessBounce(sig string, body []byte) ([]models.Bounce, error) {\n\tif len(l.hmacKey) == 0 {\n\t\treturn nil, fmt.Errorf(\"webhook key is not configured\")\n\t}\n\n\t// Parse the signature header: t={timestamp},v1={hex_signature}.\n\tts, sigHex, err := parseLettermintSignature(sig)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Verify timestamp tolerance (300 seconds).\n\tif math.Abs(float64(time.Now().Unix()-ts)) > 300 {\n\t\treturn nil, fmt.Errorf(\"signature timestamp expired\")\n\t}\n\n\t// Decode the hex signature from the header.\n\tsigB, err := hex.DecodeString(strings.TrimSpace(sigHex))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid signature encoding: %v\", err)\n\t}","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/knadh/listmonk/blob/670c01717d48647093335cc23a6be6f4b79c3b6b/internal/bounce/webhooks/lettermint.go#L29-L65","documentation":"Lettermint's ProcessBounce requires an HMAC key (set via NewLettermint) to verify webhook signatures. This error is thrown immediately when the handler was constructed with a nil or empty key, before any signature parsing occurs.","triggerScenarios":"Calling NewLettermint(nil), NewLettermint([]byte{}), or NewLettermint(key) where key comes from an empty/unset config value or environment variable, then receiving any webhook call to ProcessBounce.","commonSituations":"The Lettermint webhook signing key env var not set in the deployment; config loading silently returning an empty string on parse failure; wiring up the handler in a dev environment without credentials; a refactor passing the wrong config field (empty by default).","solutions":["Set the Lettermint webhook signing key in your configuration/environment before starting the server.","Guard at startup: fail fast if the key is empty when webhook handling is enabled, rather than failing per-request.","Check the config-loading path for silent empty defaults (e.g. viper/env readers returning \"\" when a var is missing).","Verify the correct secret is wired: NewLettermint must receive the same key Lettermint uses to sign webhooks."],"exampleFix":"// before: silently empty key\nlm := webhooks.NewLettermint([]byte(cfg.WebhookKey)) // \"\" if unset\n\n// after: fail fast at startup\nif cfg.WebhookKey == \"\" {\n    log.Fatal(\"LETTERMINT_WEBHOOK_KEY is required\")\n}\nlm := webhooks.NewLettermint([]byte(cfg.WebhookKey))","handlingStrategy":"validation","validationCode":"func mustNewLettermint(key []byte) *webhooks.Lettermint {\n    if len(key) == 0 {\n        panic(\"lettermint webhook key is required\")\n    }\n    return webhooks.NewLettermint(key)\n}","typeGuard":null,"tryCatchPattern":"bounces, err := lm.ProcessBounce(sig, body)\nif err != nil {\n    if err.Error() == \"webhook key is not configured\" {\n        // server misconfiguration: alert ops, return 500\n        log.Printf(\"configuration error: %v\", err)\n        http.Error(w, \"server misconfiguration\", http.StatusInternalServerError)\n        return\n    }\n    http.Error(w, \"bad request\", http.StatusBadRequest)\n}","preventionTips":["Fail at startup if webhook handling is enabled but the signing key is empty.","Load the key from a required config field with validation, not an optional default.","Alert/monitor for this error at runtime — it indicates deployment misconfiguration, not bad client input."],"tags":["webhook","configuration","hmac","lettermint","missing-config"],"backgroundTag":"missing-env-var","analyzedSha":"670c01717d48647093335cc23a6be6f4b79c3b6b","analyzedAt":"2026-09-01T03:39:35.452Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}