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)
continueView on GitHub (pinned to 909b515798)
Solutions
- Update crowdsec so models.Alert matches the server's schema
- Capture and inspect the raw payload to spot the schema difference
- 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
- Sync models.Alert with server schema on upgrades
- Validate decision fields (non-nil Value) before processing
- Log raw payloads when schema drift is suspected
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
- no header in message, skipping
- no source user in header message, skipping
- polling papi message format is not compatible: %+v: %w
- failed to decode response: %w
- message for '%s' contains bad data format: %w
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/c892d08bf041a114.
Report an issue: GitHub.