knadh/listmonk · error

missing validationCode in subscription payload

Error message

missing validationCode in subscription payload

What it means

After extracting the event data map, ProcessSubscription reads data["validationCode"] and returns this error when it is empty or missing. Azure's subscription validation handshake requires echoing back this code as validationResponse; without it the subscription cannot be validated.

Source

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

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

	events, err := parseAzureEvents(b)
	if err != nil {
		return nil, err
	}

View on GitHub (pinned to 670c01717d)

Solutions

  1. Register the Event Grid subscription so a genuine SubscriptionValidationEvent containing validationCode is delivered (use the Azure portal/CLI handshake, not a fabricated payload).
  2. Check the delivered event JSON and confirm data.validationCode is present and non-empty.
  3. If testing, include a non-empty validationCode in the data map.
  4. Confirm no intermediary transformation is dropping the validationCode field.

Example fix

// before
curl -X POST https://host/webhooks/azure -d '{"data":{}}'
// after
curl -X POST https://host/webhooks/azure -d '{"data":{"validationCode":"abc123"}}'
Defensive patterns

Strategy: validation

Validate before calling

var probe struct {
	Data struct {
		ValidationCode string `json:"validationCode"`
	} `json:"data"`
}
if json.Unmarshal(rawData, &probe) != nil || strings.TrimSpace(probe.Data.ValidationCode) == "" {
	// invalid validation payload; do not call ProcessSubscription
}

Type guard

func hasValidationCode(raw json.RawMessage) bool {
	var d struct {
		ValidationCode string `json:"validationCode"`
	}
	if json.Unmarshal(raw, &d) != nil { return false }
	return strings.TrimSpace(d.ValidationCode) != ""
}

Try / catch

res, err := azure.ProcessSubscription(body)
if err != nil {
	if strings.Contains(err.Error(), "missing validationCode") {
		return echo.NewHTTPError(http.StatusBadRequest, "invalid validation event")
	}
	return err
}

Prevention

When it happens

Trigger: A subscription validation event arrives whose data map has an empty or absent validationCode field — e.g. a manually crafted test payload, an event from a non-validation source routed to this handler, or whitespace-only validationCode (it is TrimSpace'd before the check).

Common situations: Testing the webhook with fake validation events lacking validationCode; Azure retries where the event was truncated; forwarding validation events through a queue/proxy that strips fields.

Related errors


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