knadh/listmonk · error
empty event payload
Error message
empty event payload
What it means
ProcessSubscription handles Azure Event Grid subscription validation webhooks. This error is returned when, after successfully parsing the webhook body, the payload contains zero events — there is nothing to validate or process. The library throws it as a guard against empty request bodies so it never indexes into a non-existent first event.
Source
Thrown at internal/bounce/webhooks/azure.go:61
}
// NewAzure returns a new Azure webhook handler.
func NewAzure(sharedSecret, sharedSecretHeader string) *Azure {
return &Azure{
sharedSecret: strings.TrimSpace(sharedSecret),
sharedSecretHeader: strings.TrimSpace(sharedSecretHeader),
}
}
// ProcessSubscription processes Event Grid subscription validation requests and
// returns the response payload that should be written to HTTP response body.
func (a *Azure) ProcessSubscription(b []byte) (json.RawMessage, error) {
events, err := parseAzureEvents(b)
if err != nil {
return nil, err
}
if len(events) == 0 {
return nil, errors.New("empty event payload")
}
// Validation code arrives in the first event for subscription validation flow.
var payload map[string]json.RawMessage
if err := json.Unmarshal(events[0].RawData, &payload); err != nil {
return nil, fmt.Errorf("error reading validation payload: %v", err)
}
rawData, ok := payload["data"]
if !ok {
return nil, errors.New("missing event data")
}
var data map[string]string
if err := json.Unmarshal(rawData, &data); err != nil {
return nil, fmt.Errorf("error reading validation data: %v", err)
}
View on GitHub (pinned to 670c01717d)
Solutions
- Send a real Azure Event Grid subscription validation event (with eventType SubscriptionValidationEvent and a validationCode) when registering the webhook.
- Return 400 without retrying if events are empty — the request is simply not an Event Grid delivery.
- Check that the Event Grid subscription points at the correct webhook endpoint.
- Add a client-side emptiness check before posting if you are driving ProcessSubscription programmatically.
Example fix
// before
res, err := azure.ProcessSubscription(body)
// after
if len(body) == 0 {
return echo.NewHTTPError(http.StatusBadRequest, "empty body")
}
res, err := azure.ProcessSubscription(body) Defensive patterns
Strategy: validation
Validate before calling
if len(body) == 0 || strings.TrimSpace(string(body)) == "" || string(body) == "[]" {
return echo.NewHTTPError(http.StatusBadRequest, "empty event payload")
} Type guard
func hasAzureEvents(b []byte) bool {
var evts []struct{ RawData json.RawMessage `json:"data"` }
return json.Unmarshal(b, &evts) == nil && len(evts) > 0
} Try / catch
res, err := azure.ProcessSubscription(body)
if err != nil {
if strings.Contains(err.Error(), "empty event payload") {
return echo.NewHTTPError(http.StatusBadRequest, "no events") // do not retry
}
return err
} Prevention
- Configure uptime probes to use a dedicated health endpoint, not the webhook URL.
- Validate Event Grid subscription registration sends a real validation event.
- Log the raw body (truncated) for requests rejected as empty.
- Reject empty bodies at the HTTP layer before invoking ProcessSubscription.
When it happens
Trigger: An HTTP POST reaches the Azure bounce webhook endpoint whose body parses (via parseAzureEvents) into an empty event array — e.g. an empty JSON array [], an empty body that parses cleanly, or a health-check/probe request hitting the webhook URL.
Common situations: Load balancer or uptime probes POSTing empty bodies to the webhook endpoint; a misconfigured Azure Event Grid subscription delivering an empty batch; testing the endpoint with curl and no body.
Related errors
- error reading validation data: %v
- missing event data
- missing validationCode in subscription payload
- missing azure event grid request context
- invalid azure event grid shared secret
AI-assisted analysis of knadh/listmonk@670c01717d (2026-09-01).
Data as JSON: /api/errors/f86ea8e2aebaad3d.
Report an issue: GitHub.