{"record":{"id":"1a7bed0837fbd0eb","repo":"crowdsecurity/crowdsec","slug":"machine-s-w","errorCode":null,"errorMessage":"machine '%s': %w","messagePattern":"machine '(.+?)': %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/database/alerts.go","lineNumber":734,"sourceCode":"\n\tif err := tx.Commit(); err != nil {\n\t\treturn nil, fmt.Errorf(\"committing alert transaction: %w: %w\", err, BulkError)\n\t}\n\n\treturn ids, nil\n}\n\nfunc (c *Client) CreateAlert(ctx context.Context, machineID string, alertList []*models.Alert) ([]string, error) {\n\tvar (\n\t\towner *ent.Machine\n\t\terr   error\n\t)\n\n\tif machineID != \"\" {\n\t\towner, err = c.QueryMachineByID(ctx, machineID)\n\t\tif err != nil {\n\t\t\tif !errors.Is(err, UserNotExists) {\n\t\t\t\treturn nil, fmt.Errorf(\"machine '%s': %w\", machineID, err)\n\t\t\t}\n\n\t\t\tc.Log.Debugf(\"creating alert: machine %s doesn't exist\", machineID)\n\n\t\t\towner = nil\n\t\t}\n\t}\n\n\tc.Log.Debugf(\"writing %d items\", len(alertList))\n\n\talertIDs := []string{}\n\tif err := slicetools.Batch(ctx, alertList, alertCreateBulkSize, func(ctx context.Context, part []*models.Alert) error {\n\t\tids, err := c.createAlertBatch(ctx, machineID, owner, part)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"machine %q: %w\", machineID, err)\n\t\t}\n\t\talertIDs = append(alertIDs, ids...)\n\t\treturn nil","sourceCodeStart":716,"sourceCodeEnd":752,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/database/alerts.go#L716-L752","documentation":"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.","triggerScenarios":"CreateAlert/CreateOrUpdateAlert called with a machineID whose QueryMachineByID fails with an error other than UserNotExists (DB connectivity failure, ent query error, context cancellation).","commonSituations":"Database down or migrated mid-push; alerts pushed by a machine during a context timeout; MySQL/SQLite connection pool exhausted on busy LAPI instances.","solutions":["Check the wrapped cause with errors.Is/errors.As to see the real DB error","Verify database connectivity and credentials in crowdsec.yaml (db_config)","Retry the push; transient DB failures often resolve once the pool recovers","If the machine should exist, confirm it with `cscli machines list` and re-register if needed"],"exampleFix":"// before\nif !errors.Is(err, UserNotExists) {\n    return nil, fmt.Errorf(\"machine '%s': %w\", machineID, err)\n}\n// after (only if treating missing machine as fatal is wrong for your flow)\nif !errors.Is(err, UserNotExists) {\n    if errors.Is(err, context.DeadlineExceeded) {\n        return nil, fmt.Errorf(\"machine '%s': lookup timed out, retry push: %w\", machineID, err)\n    }\n    return nil, fmt.Errorf(\"machine '%s': %w\", machineID, err)\n}","handlingStrategy":"try-catch","validationCode":"if machineID == \"\" {\n    return errors.New(\"machineID required to attribute alert\")\n}","typeGuard":null,"tryCatchPattern":"alertIDs, err := client.CreateAlert(ctx, alert)\nif err != nil {\n    if strings.HasPrefix(err.Error(), \"machine '\") {\n        // inspect wrapped cause via errors.Is/As\n    }\n    return fmt.Errorf(\"create alert: %w\", err)\n}","preventionTips":["Ensure the machine is registered (cscli machines add) before pushing alerts","Keep DB credentials and connectivity validated at startup","Pass a context with adequate timeout for alert pushes"],"tags":["database","crowdsec","alerts"],"backgroundTag":"database-query-failed","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}