crowdsecurity/crowdsec · error

message for '%s' contains bad alert format: %w

Error message

message for '%s' contains bad alert format: %w

What it means

A PAPI (console) message carrying an alert 'add' command had a Data field that could not be unmarshalled into models.Alert after a round-trip through json.Marshal. The message header/operation was valid; the payload body does not match the Alert schema expected by this crowdsec version.

Source

Thrown at pkg/apiserver/papi_cmd.go:101

	default:
		return fmt.Errorf("unknown command '%s' for operation type '%s'", message.Header.OperationCmd, message.Header.OperationType)
	}

	return nil
}

func AlertCmd(ctx context.Context, message *Message, p *Papi, sync bool) error {
	switch message.Header.OperationCmd {
	case "add":
		data, err := json.Marshal(message.Data)
		if err != nil {
			return err
		}

		alert := &models.Alert{}

		if err := json.Unmarshal(data, alert); err != nil {
			return fmt.Errorf("message for '%s' contains bad alert format: %w", message.Header.OperationType, err)
		}

		log.Infof("Received order %s from PAPI (%d decisions)", alert.UUID, len(alert.Decisions))
		decisionsToKeep := make([]*models.Decision, 0)
		for _, decision := range alert.Decisions {
			if decision.Value == nil {
				continue
			}
			isAllowlisted, reason, err := p.DBClient.IsAllowlisted(ctx, *decision.Value)
			if err != nil {
				log.Errorf("Failed to check if decision '%s' is allowlisted: %s", *decision.Value, err)
				// keep the decision in case of error during allowlist check
				decisionsToKeep = append(decisionsToKeep, decision)
				continue
			}
			if isAllowlisted {
				log.Infof("Decision '%s' is allowlisted, removing it (%s)", *decision.Value, reason)
				continue

View on GitHub (pinned to 909b515798)

Solutions

  1. Update crowdsec so models.Alert matches the server's schema
  2. Capture and inspect the raw payload to spot the schema difference
  3. Verify the sender is an official crowdsec component
Defensive patterns

Strategy: try-catch

Validate before calling

var probe map[string]any; if err := json.Unmarshal(data, &probe); err != nil { return err }; if _, ok := probe["decisions"]; !ok { return fmt.Errorf("alert payload missing decisions") }

Type guard

func isAlertShape(m map[string]any) bool { _, hasUUID := m["uuid"]; _, hasDecisions := m["decisions"]; return hasUUID && hasDecisions }

Try / catch

if err := AlertCmd(ctx, msg, p, false); err != nil { if strings.Contains(err.Error(), "bad alert format") { log.Errorf("invalid alert from PAPI: %v", err) } }

Prevention

When it happens

Trigger: json.Unmarshal(data, alert) fails on an alert message: schema drift between sender and consumer, malformed JSON, or wrong field types.

Common situations: CAPI/PAPI server newer than the local crowdsec sending extended Alert structures, intercepted/corrupted message payload, custom sender producing non-standard alerts.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/c892d08bf041a114. Report an issue: GitHub.