knadh/listmonk · critical
webhook key is not configured
Error message
webhook key is not configured
What it means
Forwardemail.ProcessBounce verifies webhook payloads with HMAC-SHA256 using an hmacKey supplied at construction (NewForwardemail). This error is returned when that key is empty (len == 0), meaning no verification is possible. The library refuses to process rather than skipping signature verification, which would be a security hole.
Source
Thrown at internal/bounce/webhooks/forwardemail.go:51
ResponseCode int `json:"response_code"`
TruthSource string `json:"truth_source"`
Headers map[string]string `json:"headers"`
Bounce BounceDetails `json:"bounce"`
BouncedAt time.Time `json:"bounced_at"`
}
// Forwardemail handles webhook notifications (mainly bounce notifications).
type Forwardemail struct {
hmacKey []byte
}
func NewForwardemail(key []byte) *Forwardemail {
return &Forwardemail{hmacKey: key}
}
func (p *Forwardemail) ProcessBounce(sigHex string, body []byte) ([]models.Bounce, error) {
if len(p.hmacKey) == 0 {
return nil, errors.New("webhook key is not configured")
}
// Decode the hex-encoded signature from the webhook
sig, err := hex.DecodeString(sigHex)
if err != nil {
return nil, fmt.Errorf("invalid signature encoding: %v", err)
}
// Generate HMAC using the request body and secret key
mac := hmac.New(sha256.New, p.hmacKey)
mac.Write(body)
expectedSignature := mac.Sum(nil)
// Compare the generated signature with the provided signature
if !hmac.Equal(expectedSignature, sig) {
return nil, errors.New("invalid signature")
}
View on GitHub (pinned to 670c01717d)
Solutions
- Set the Forwardemail webhook key in your configuration/environment and restart so NewForwardemail receives a non-empty key.
- Copy the webhook signing secret from your Forwardemail account/dashboard into the deployment secrets store.
- Check the code path that reads the key and fails loudly at startup (validate len(key) > 0 when constructing NewForwardemail) instead of at first webhook.
- Verify secrets mounts/env propagation (Docker secret file, k8s secret) actually populated the variable.
Example fix
// before
key := os.Getenv("FORWARD_EMAIL_KEY") // "" if unset
p := webhooks.NewForwardemail([]byte(key))
// after
key := os.Getenv("FORWARD_EMAIL_KEY")
if key == "" {
log.Fatal("FORWARD_EMAIL_KEY must be set")
}
p := webhooks.NewForwardemail([]byte(key)) Defensive patterns
Strategy: validation
Validate before calling
key := os.Getenv("FORWARD_EMAIL_WEBHOOK_KEY")
if key == "" {
return errors.New("forwardemail webhook key must be configured before processing bounces")
} Type guard
func forwardemailConfigured(p *webhooks.Forwardemail) bool {
return p != nil // combine with non-empty key check at construction time
} Try / catch
bounces, err := p.ProcessBounce(sigHex, body)
if err != nil {
if strings.Contains(err.Error(), "webhook key is not configured") {
// deployment misconfiguration: alert ops, return 503
return echo.NewHTTPError(http.StatusServiceUnavailable, "webhook not configured")
}
return err
} Prevention
- Validate the key is non-empty at startup, when calling NewForwardemail, and fail fast.
- Provision the secret in every environment (staging, dev) via your secrets manager.
- Check Docker/K8s secret mounts actually populate the env var.
- Add a smoke test that constructs the webhook with the production config shape.
When it happens
Trigger: Forwardemail was constructed as NewForwardemail(nil) or NewForwardemail([]byte{}) — typically because the webhook key config value/env var was empty — and then ProcessBounce is called with an incoming signature and body.
Common situations: Missing FORWARD_EMAIL_WEBHOOK_KEY-style env var in the deployment; config key omitted or empty string in the config file; a fresh environment (staging, local dev) where secrets were never provisioned; Docker/secret-mount failed so the value reads as empty.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- invalid signature
- invalid signature encoding: %v
- invalid azure event grid shared secret
- error unmarshalling Forwardemail notification: %v
- webhook key is not configured
AI-assisted analysis of knadh/listmonk@670c01717d (2026-09-01).
Data as JSON: /api/errors/4ebe9602e1253c94.
Report an issue: GitHub.