crowdsecurity/crowdsec · error

unable to create alert: no IDs returned for alert %s

Error message

unable to create alert: no IDs returned for alert %s

What it means

A defensive invariant check: after CreateAlert reports success, the code expects at least one alert ID back. If the returned ID slice is empty (marked 'happy nilaway'), it returns 'unable to create alert: no IDs returned for alert %s'. This indicates an internal inconsistency — CreateAlert succeeded but returned no identifier — rather than a user-facing input problem.

Source

Thrown at pkg/database/alerts.go:64

	if alertItem.UUID == "" {
		return "", errors.New("alert UUID is empty")
	}

	alerts, err := c.Ent.Alert.Query().Where(alert.UUID(alertItem.UUID)).WithDecisions().All(ctx)
	if err != nil && !ent.IsNotFound(err) {
		return "", fmt.Errorf("unable to query alerts for uuid %s: %w", alertItem.UUID, err)
	}

	// alert wasn't found, insert it (expected hotpath)
	if ent.IsNotFound(err) || len(alerts) == 0 {
		alertIDs, err := c.CreateAlert(ctx, machineID, []*models.Alert{alertItem})
		if err != nil {
			return "", fmt.Errorf("unable to create alert: %w", err)
		}

		// happy nilaway
		if len(alertIDs) == 0 {
			return "", fmt.Errorf("unable to create alert: no IDs returned for alert %s", alertItem.UUID)
		}

		return alertIDs[0], nil
	}

	// this should never happen
	if len(alerts) > 1 {
		return "", fmt.Errorf("multiple alerts found for uuid %s", alertItem.UUID)
	}

	log.Infof("Alert %s already exists, checking associated decisions", alertItem.UUID)

	// alert is found, check for any missing decisions

	newUuids := make([]string, len(alertItem.Decisions))
	for i, decItem := range alertItem.Decisions {
		newUuids[i] = decItem.UUID
	}

View on GitHub (pinned to 909b515798)

Solutions

  1. Retry the alert push; the UUID lookup makes it idempotent
  2. Check the crowdsec version for known CreateAlert bugs and upgrade
  3. Capture logs and report upstream (github.com/crowdsec/crowdsec/issues) with the crowdsec version and DB backend
  4. Verify with 'cscli alerts list' whether the alert was actually persisted despite the empty ID list
Defensive patterns

Strategy: fallback

Try / catch

id, err := client.CreateOrUpdateAlert(ctx, machineID, alert)
if err != nil && strings.Contains(err.Error(), "no IDs returned") {
    // verify actual persistence instead of trusting the ID
    alerts, qErr := client.QueryAlertWithUUID(ctx, alert.UUID)
    if qErr == nil && len(alerts) == 1 { id = alerts[0].UUID }
}

Prevention

When it happens

Trigger: CreateAlert returns a non-nil, empty []string ID slice for a freshly inserted alert. Should be unreachable in normal operation; would occur only from an internal regression in CreateAlert's bulk-insert ID collection logic.

Common situations: Essentially only seen after a crowdsec bug or a modified/custom build; if encountered, it points to a defect in the alert insertion code path rather than to user configuration.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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