{"record":{"id":"c782abad53a48f18","repo":"crowdsecurity/crowdsec","slug":"while-saving-alert-from-blocklist-s-w","errorCode":null,"errorMessage":"while saving alert from blocklist %s: %w","messagePattern":"while saving alert from blocklist (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/apiserver/apic.go","lineNumber":1003,"sourceCode":"\n\terr = a.dbClient.SetConfigItem(ctx, blocklistConfigItemName, time.Now().UTC().Format(http.TimeFormat))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"while setting last pull timestamp for blocklist %s: %w\", *blocklist.Name, err)\n\t}\n\n\tif len(decisions) == 0 {\n\t\tlog.Infof(\"blocklist %s has no decisions\", *blocklist.Name)\n\t\treturn nil\n\t}\n\t// apply APIC specific whitelists\n\tdecisions = a.ApplyApicWhitelists(ctx, decisions)\n\talert := createAlertForDecision(decisions[0], types.CAPIAlertKind)\n\talertsFromCapi := []*models.Alert{alert}\n\talertsFromCapi = fillAlertsWithDecisions(alertsFromCapi, decisions, addCounters)\n\n\terr = a.SaveAlerts(ctx, alertsFromCapi, addCounters, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"while saving alert from blocklist %s: %w\", *blocklist.Name, err)\n\t}\n\n\treturn nil\n}\n\nfunc (a *apic) UpdateBlocklists(ctx context.Context, blocklists []*modelscapi.BlocklistLink, addCounters map[string]map[string]int, forcePull bool) error {\n\tif len(blocklists) == 0 {\n\t\treturn nil\n\t}\n\n\t// we must use a different http client than apiClient's because the transport of apiClient is jwtTransport or here we have signed apis that are incompatibles\n\t// we can use the same baseUrl as the urls are absolute and the parse will take care of it\n\tdefaultClient, err := apiclient.NewDefaultClient(a.apiClient.BaseURL, \"\", \"\", nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"while creating default client: %w\", err)\n\t}\n\n\tfor _, blocklist := range blocklists {","sourceCodeStart":985,"sourceCodeEnd":1021,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/apiserver/apic.go#L985-L1021","documentation":"Wraps errors returned by a.SaveAlerts when persisting the alert built from the pulled blocklist decisions. SaveAlerts writes the alert plus decisions (and optional counters) to the database, so the wrapped error is a DB write failure during blocklist import.","triggerScenarios":"updateBlocklist fetched non-empty decisions, builds createAlertForDecision(...CAPIAlertKind) and calls SaveAlerts; the insert fails due to DB outage, context timeout, SQLite lock, or malformed decision data.","commonSituations":"Large blocklist insert exceeding SQLite lock timeout without WAL, PostgreSQL connection drop, disk full, context cancelled by shutdown during pull.","solutions":["Read the inner error from SaveAlerts for the specific DB cause.","Enable WAL mode: `cscli db enable-wal`; run `cscli db doctor`.","Check disk space and DB connectivity.","Retry the pull cycle; alerts are idempotent per blocklist alert."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// pre-check: cscli db doctor && cscli db enable-wal","typeGuard":null,"tryCatchPattern":"if err := a.SaveAlerts(ctx, alertsFromCapi, addCounters, nil); err != nil {\n    log.Warnf(\"saving blocklist alert failed, will retry next pull: %v\", err)\n    return err\n}","preventionTips":["Enable WAL mode before enabling large community blocklists.","Avoid stopping crowdsec mid-pull (use graceful shutdown).","Ensure adequate disk space for blocklist-sized alert batches.","Run migrations after upgrades."],"tags":["database","alert","blocklist","capi","write"],"backgroundTag":"database-write-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"}