{"record":{"id":"0a8c45bf7c5e8ab8","repo":"stamparm/maltrail","slug":"condensed-observable-store-prune-failed-e","errorCode":null,"errorMessage":"condensed observable store: prune failed ({e})","messagePattern":"condensed observable store: prune failed \\((.+?)\\)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sensor/src/main.rs","lineNumber":974,"sourceCode":"/// need a line per hour saying nothing was over budget. A failure IS reported, because a store\n/// that cannot be pruned will grow without bound.\nfn prune_condensed_store(cfg: &Config) {\n    if !cfg.use_condensed_storage {\n        return;\n    }\n    let path = maltrail_sensor::meta::meta_db_path(&cfg.log_dir);\n    match maltrail_sensor::meta::prune(&path, maltrail_sensor::settings::META_MAX_ROWS) {\n        Ok(0) => {}\n        Ok(deleted) => {\n            if !cfg.quiet {\n                cprintln!(\n                    \"[i] condensed observable store: pruned {deleted} lowest-value rows to the \\\n                     {} row budget\",\n                    maltrail_sensor::settings::META_MAX_ROWS\n                );\n            }\n        }\n        Err(e) => output::log_error(&format!(\"condensed observable store: prune failed ({e})\"), true),\n    }\n}\n\n/// One trail-update cycle plus the reporting around it (`sensor.py:init():update_timer()`).\n///\n/// `startup` distinguishes the synchronous refresh before the first load from the periodic one.\n/// A failure is never fatal: the sensor continues with whatever trails it already has, but says\n/// so loudly, because running on stale trails means silently missing detections.\nfn refresh_trails(cfg: &Config, quiet: bool, startup: bool) {\n    match trailupdate::run(cfg) {\n        trailupdate::Outcome::Updated => {\n            if !quiet && !startup {\n                cprintln!(\"[i] trails updated\");\n            }\n        }\n        trailupdate::Outcome::Disabled => {\n            if !quiet && startup {\n                cprintln!(","sourceCodeStart":956,"sourceCodeEnd":992,"githubUrl":"https://github.com/stamparm/maltrail/blob/77cfb06d7606506d101bbcec0786c77166c4255e/sensor/src/main.rs#L956-L992","documentation":"The sensor's condensed observable store maintenance failed during its prune step. prune_condensed_store deletes the lowest-value rows to keep the store within META_MAX_ROWS; on Err(e) it logs \"condensed observable store: prune failed ({e})\" with log_error. Unpruned rows can grow the store unboundedly across cycles.","triggerScenarios":"The DELETE/prune SQL or storage operation against the condensed observable store returns Err(e): database file locked, disk full, I/O error, or corrupted store database.","commonSituations":"Disk exhaustion on the sensor host preventing writes; SQLite-style 'database is locked' from concurrent readers/writers; permission problems on the store file after a user change; filesystem errors on removable/overlay storage in containers.","solutions":["Read the ({e}) detail to identify the storage failure (lock vs disk vs permissions).","Check free disk space and the store file's write permissions.","Stop competing processes holding a lock on the store database and retry.","Back up or recreate the condensed store file if it is corrupted."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// preflight storage before prune\nlet meta = std::fs::metadata(&store_path)?;\nassert!(!read_only(&meta.permissions()), \"store file must be writable\");\n// ensure disk headroom\nlet free = free_disk_bytes(store_dir)?;\nassert!(free > 64 * 1024 * 1024, \"insufficient disk for prune\");","typeGuard":"fn store_writable(path: &Path) -> bool {\n    path.is_file() && std::fs::OpenOptions::new().append(true).open(path).is_ok()\n}","tryCatchPattern":"if let Err(e) = prune_condensed_store(&store) {\n    log_prune_failure(&e);\n    alert_ops(\"condensed store prune failed; storage growth possible\");\n}","preventionTips":["Monitor disk space and store row count against META_MAX_ROWS","Avoid concurrent writers to the store database","Keep the store on reliable local storage, not overlay/removable mounts"],"tags":["rust","database","prune","storage"],"backgroundTag":"database-write-failed","analyzedSha":"77cfb06d7606506d101bbcec0786c77166c4255e","analyzedAt":"2026-09-13T03:50:16.010Z","contentChangedAt":"2026-09-13T03:50:16.010Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}