crowdsecurity/crowdsec · error

machine '%s': %w

Error message

machine '%s': %w

What it means

CreateAlert wraps any error returned by QueryMachineByID when looking up the alert's owning machine. The wrapper preserves the underlying cause (%w) while stating which machine the lookup failed for. Note it is deliberately NOT raised when the error is the sentinel UserNotExists — that case just means the machine has no owner record and the alert is created ownerless.

Source

Thrown at pkg/database/alerts.go:734

	if err := tx.Commit(); err != nil {
		return nil, fmt.Errorf("committing alert transaction: %w: %w", err, BulkError)
	}

	return ids, nil
}

func (c *Client) CreateAlert(ctx context.Context, machineID string, alertList []*models.Alert) ([]string, error) {
	var (
		owner *ent.Machine
		err   error
	)

	if machineID != "" {
		owner, err = c.QueryMachineByID(ctx, machineID)
		if err != nil {
			if !errors.Is(err, UserNotExists) {
				return nil, fmt.Errorf("machine '%s': %w", machineID, err)
			}

			c.Log.Debugf("creating alert: machine %s doesn't exist", machineID)

			owner = nil
		}
	}

	c.Log.Debugf("writing %d items", len(alertList))

	alertIDs := []string{}
	if err := slicetools.Batch(ctx, alertList, alertCreateBulkSize, func(ctx context.Context, part []*models.Alert) error {
		ids, err := c.createAlertBatch(ctx, machineID, owner, part)
		if err != nil {
			return fmt.Errorf("machine %q: %w", machineID, err)
		}
		alertIDs = append(alertIDs, ids...)
		return nil

View on GitHub (pinned to 909b515798)

Solutions

  1. Check the wrapped cause with errors.Is/errors.As to see the real DB error
  2. Verify database connectivity and credentials in crowdsec.yaml (db_config)
  3. Retry the push; transient DB failures often resolve once the pool recovers
  4. If the machine should exist, confirm it with `cscli machines list` and re-register if needed

Example fix

// before
if !errors.Is(err, UserNotExists) {
    return nil, fmt.Errorf("machine '%s': %w", machineID, err)
}
// after (only if treating missing machine as fatal is wrong for your flow)
if !errors.Is(err, UserNotExists) {
    if errors.Is(err, context.DeadlineExceeded) {
        return nil, fmt.Errorf("machine '%s': lookup timed out, retry push: %w", machineID, err)
    }
    return nil, fmt.Errorf("machine '%s': %w", machineID, err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if machineID == "" {
    return errors.New("machineID required to attribute alert")
}

Try / catch

alertIDs, err := client.CreateAlert(ctx, alert)
if err != nil {
    if strings.HasPrefix(err.Error(), "machine '") {
        // inspect wrapped cause via errors.Is/As
    }
    return fmt.Errorf("create alert: %w", err)
}

Prevention

When it happens

Trigger: CreateAlert/CreateOrUpdateAlert called with a machineID whose QueryMachineByID fails with an error other than UserNotExists (DB connectivity failure, ent query error, context cancellation).

Common situations: Database down or migrated mid-push; alerts pushed by a machine during a context timeout; MySQL/SQLite connection pool exhausted on busy LAPI instances.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


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