{"record":{"id":"44aa310afcb4e3de","repo":"crowdsecurity/crowdsec","slug":"while-getting-last-pull-timestamp-for-blocklist-s","errorCode":null,"errorMessage":"while getting last pull timestamp for blocklist %s: %w","messagePattern":"while getting last pull timestamp for blocklist (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/apiserver/apic.go","lineNumber":967,"sourceCode":"\t\t_forcePull, err := a.ShouldForcePullBlocklist(ctx, blocklist)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"while checking if we should force pull blocklist %s: %w\", *blocklist.Name, err)\n\t\t}\n\n\t\tforcePull = _forcePull\n\t}\n\n\tblocklistConfigItemName := fmt.Sprintf(\"blocklist:%s:last_pull\", *blocklist.Name)\n\n\tvar (\n\t\tlastPullTimestamp string\n\t\terr               error\n\t)\n\n\tif !forcePull {\n\t\tlastPullTimestamp, err = a.dbClient.GetConfigItem(ctx, blocklistConfigItemName)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"while getting last pull timestamp for blocklist %s: %w\", *blocklist.Name, err)\n\t\t}\n\t}\n\n\tdecisions, hasChanged, err := client.Decisions.GetDecisionsFromBlocklist(ctx, blocklist, lastPullTimestamp)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"while getting decisions from blocklist %s: %w\", *blocklist.Name, err)\n\t}\n\n\tif !hasChanged {\n\t\tif lastPullTimestamp == \"\" {\n\t\t\tlog.Infof(\"blocklist %s hasn't been modified or there was an error reading it, skipping\", *blocklist.Name)\n\t\t} else {\n\t\t\tlog.Infof(\"blocklist %s hasn't been modified since %s, skipping\", *blocklist.Name, lastPullTimestamp)\n\t\t}\n\n\t\treturn nil\n\t}\n","sourceCodeStart":949,"sourceCodeEnd":985,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/apiserver/apic.go#L949-L985","documentation":"Wraps the error from dbClient.GetConfigItem for the per-blocklist `blocklist:<name>:last_pull` config item. Only force-pulled blocklists skip this lookup. It records when the blocklist was last fetched; a failed read can indicate a DB problem or a config-item storage issue.","triggerScenarios":"updateBlocklist without forcePull queries the config item and the DB read fails (DB down, context cancelled, ent query error).","commonSituations":"SQLite/PostgreSQL unavailable mid-cycle, DB corruption of config_items table, interrupted migration leaving the table inaccessible.","solutions":["Check DB connectivity and health (`cscli db doctor`).","If the item is genuinely missing this is not an error — NotFound is returned as empty string by the caller, so inspect the wrapped error for the real cause.","Enable SQLite WAL mode.","Re-run the pull once the database is healthy; the timestamp will be re-read next cycle."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// check DB health before pull: cscli db doctor","typeGuard":null,"tryCatchPattern":"lastPullTimestamp, err = a.dbClient.GetConfigItem(ctx, name)\nif err != nil {\n    if ent.IsNotFound(err) { lastPullTimestamp = \"\" } else { return err }\n}","preventionTips":["Treat missing config items as 'never pulled' (empty timestamp).","Avoid manual edits to the config_items table.","Enable WAL mode for SQLite."],"tags":["database","config-item","blocklist","pull-timestamp"],"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-14T05:17:10.506Z"}