knadh/listmonk · error
missing azure event grid request context
Error message
missing azure event grid request context
What it means
verifyAuth, called by ProcessBounce, authenticates Azure Event Grid deliveries only when a shared secret is configured. This error is returned when a shared secret IS configured but the function receives a nil *http.Request, meaning there is no request context (query param or header) against which to verify the secret. It protects the strict-auth path from silently passing or panicking.
Source
Thrown at internal/bounce/webhooks/azure.go:153
})
}
return out, nil
}
func (a *Azure) verifyAuth(req *http.Request) error {
const (
defaultSecretHeader = "X-Listmonk-Webhook-Secret"
querySecretParam = "code"
)
// If no local credential is configured, allow webhook payloads.
if a.sharedSecret == "" {
return nil
}
if req == nil {
return errors.New("missing azure event grid request context")
}
querySecret := strings.TrimSpace(req.URL.Query().Get(querySecretParam))
if secretsEqual(a.sharedSecret, querySecret) {
return nil
}
headerName := a.sharedSecretHeader
if headerName == "" {
headerName = defaultSecretHeader
}
headerSecret := strings.TrimSpace(req.Header.Get(headerName))
if secretsEqual(a.sharedSecret, headerSecret) {
return nil
}
return errors.New("invalid azure event grid shared secret")
}View on GitHub (pinned to 670c01717d)
Solutions
- Pass the original inbound *http.Request to ProcessBounce so verifyAuth can read the secret from the query param or header.
- If invoking outside HTTP (queue replay), fetch the stored secret value and provide a reconstructed request, or temporarily run that path without a configured shared secret.
- In tests, either set no shared secret (NewAzure with empty secret) or pass an httptest.Request with the secret attached.
- Review call sites of ProcessBounce to ensure none omit the request after the auth feature was added.
Example fix
// before bounces, err := azure.ProcessBounce(body, nil) // after bounces, err := azure.ProcessBounce(body, c.Request())
Defensive patterns
Strategy: try-catch
Validate before calling
if req == nil && os.Getenv("AZURE_WEBHOOK_SECRET") != "" {
// shared secret configured but no request context: refuse before calling ProcessBounce
} Type guard
func canVerifyAzure(azure *webhooks.Azure, req *http.Request) bool {
return req != nil // or reflect on configured secret if exposed
} Try / catch
bounces, err := azure.ProcessBounce(body, req)
if err != nil {
if strings.Contains(err.Error(), "missing azure event grid request context") {
log.Printf("azure webhook called without request context; check call site: %v", err)
}
return err
} Prevention
- Always pass the inbound *http.Request into ProcessBounce in HTTP handlers (c.Request()).
- In queue-replay workers, reconstruct an *http.Request carrying the stored secret.
- In unit tests, configure the webhook without a shared secret or use httptest requests.
- Add a startup/CI assertion that no call site passes nil where a secret is configured.
When it happens
Trigger: The Azure webhook is constructed with a shared secret, but ProcessBounce is invoked (e.g. programmatically or from a queue worker replaying stored payloads) without passing the original *http.Request, so verifyAuth gets nil.
Common situations: Replaying stored webhook bodies in tests or a redelivery worker without the original request; refactoring changed the call site to drop the request parameter; unit tests calling ProcessBounce directly while the deployment has a shared secret configured.
Related errors
- invalid azure event grid shared secret
- empty event payload
- missing event data
- missing validationCode in subscription payload
- error reading validation data: %v
AI-assisted analysis of knadh/listmonk@670c01717d (2026-09-01).
Data as JSON: /api/errors/35f1c889e7f6fac8.
Report an issue: GitHub.