knadh/listmonk · error

error reading validation data: %v

Error message

error reading validation data: %v

What it means

ProcessSubscription validates Azure Event Grid subscription handshake requests. After parsing the event array, it extracts the `data` field of the first event and unmarshals it into map[string]string. This error is thrown when that `data` object cannot be decoded as a flat JSON object of string values — meaning the payload is not a well-formed subscription validation event.

Source

Thrown at internal/bounce/webhooks/azure.go:77

	}
	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)
	}

	code := strings.TrimSpace(data["validationCode"])
	if code == "" {
		return nil, errors.New("missing validationCode in subscription payload")
	}

	res, _ := json.Marshal(map[string]string{
		"validationResponse": code,
	})
	return json.RawMessage(res), nil
}

// ProcessBounce parses Azure Event Grid email delivery events and returns bounce entries.
func (a *Azure) ProcessBounce(req *http.Request, b []byte) ([]models.Bounce, error) {
	if err := a.verifyAuth(req); err != nil {
		return nil, err
	}

View on GitHub (pinned to 670c01717d)

Solutions

  1. Ensure only Event Grid 'Microsoft.EventGrid.SubscriptionValidationEvent' payloads are POSTed to the subscription-validation handler; route delivery-report events to ProcessBounce instead.
  2. Validate the incoming body is a JSON array whose first element contains data.validationCode as a string before calling ProcessSubscription.
  3. Log the raw request body on failure to inspect the actual shape of the `data` field.
  4. Check the Event Grid subscription is configured for the Azure Communication Services email events schema you expect.

Example fix

// before: posting a delivery-report event to the validation endpoint
body := `[{"eventType":"Microsoft.Communication.EmailDeliveryReportReceived","data":{"recipient":"a@b.com","status":"Failed"}}]`
res, err := azure.ProcessSubscription([]byte(body)) // error reading validation data

// after: post a proper validation event
body := `[{"eventType":"Microsoft.EventGrid.SubscriptionValidationEvent","data":{"validationCode":"abc123"}}]`
res, err := azure.ProcessSubscription([]byte(body)) // returns {"validationResponse":"abc123"}
Defensive patterns

Strategy: validation

Validate before calling

func isValidSubscriptionValidation(body []byte) bool {
    var evs []struct {
        Data struct {
            ValidationCode string `json:"validationCode"`
        } `json:"data"`
    }
    return json.Unmarshal(body, &evs) == nil && len(evs) > 0 && evs[0].Data.ValidationCode != ""
}

Type guard

func isStringMap(m json.RawMessage) bool {
    var v map[string]string
    return json.Unmarshal(m, &v) == nil
}

Try / catch

res, err := azure.ProcessSubscription(body)
if err != nil {
    log.Printf("subscription validation failed: %v; body=%s", err, body)
    http.Error(w, "invalid subscription validation payload", http.StatusBadRequest)
    return
}

Prevention

When it happens

Trigger: Calling ProcessSubscription with a body whose first event's `data` field is absent-but-typed-differently, a nested object (e.g. a real EmailDeliveryReport data payload with structured fields instead of flat strings), an array, or a JSON literal like a number/string/bool rather than an object.

Common situations: Routing bounce notifications (Microsoft.Communication.EmailDeliveryReportReceived events) to the subscription-validation endpoint by mistake; Event Grid re-sending validation with a schema version whose data contains non-string fields; a proxy or test curl command posting hand-crafted JSON; Azure retrying an old event format after provider schema updates.

Related errors


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