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

  1. Send a real Azure Event Grid subscription validation event (with eventType SubscriptionValidationEvent and a validationCode) when registering the webhook.
  2. Return 400 without retrying if events are empty — the request is simply not an Event Grid delivery.
  3. Check that the Event Grid subscription points at the correct webhook endpoint.
  4. 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

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


AI-assisted analysis of knadh/listmonk@670c01717d (2026-09-01). Data as JSON: /api/errors/f86ea8e2aebaad3d. Report an issue: GitHub.