{"record":{"id":"8640abaefad19c3b","repo":"zeroclaw-labs/zeroclaw","slug":"invalid-memory-policy-threat-scan-on-hit-value-ot","errorCode":null,"errorMessage":"invalid memory.policy.threat_scan_on_hit value {other:?}; expected reject or block-on-read","messagePattern":"invalid memory\\.policy\\.threat_scan_on_hit value (.+?); expected reject or block-on-read","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-memory/src/scanned.rs","lineNumber":105,"sourceCode":"            \"on\" => Ok(ThreatScanMode::On),\n            \"strict\" => Ok(ThreatScanMode::Strict),\n            other => anyhow::bail!(\n                \"invalid memory.policy.threat_scan value {other:?}; expected off, on, or strict\"\n            ),\n        }\n    }\n\n    fn on_hit(&self) -> anyhow::Result<OnHit> {\n        match self\n            .policy\n            .threat_scan_on_hit\n            .trim()\n            .to_ascii_lowercase()\n            .as_str()\n        {\n            \"reject\" => Ok(OnHit::Reject),\n            \"block-on-read\" | \"block_on_read\" => Ok(OnHit::BlockOnRead),\n            other => anyhow::bail!(\n                \"invalid memory.policy.threat_scan_on_hit value {other:?}; expected reject or block-on-read\"\n            ),\n        }\n    }\n\n    fn scan_scope(&self) -> anyhow::Result<Option<Scope>> {\n        Ok(match self.scan_mode()? {\n            ThreatScanMode::Off => None,\n            ThreatScanMode::On => Some(Scope::On),\n            ThreatScanMode::Strict => Some(Scope::Strict),\n        })\n    }\n\n    /// Scope for read-time re-scanning; `None` disables read filtering.\n    fn read_scope(&self) -> anyhow::Result<Option<Scope>> {\n        if !self.policy.threat_scan_load_time {\n            return Ok(None);\n        }","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-memory/src/scanned.rs#L87-L123","documentation":"ScannedMemory::on_hit() parses [memory.policy].threat_scan_on_hit: trimmed, lowercased, matched against reject | block-on-read (underscore block_on_read also accepted). It is only consulted when threat_scan is on/strict, so an invalid value surfaces on the first scanned write rather than at config load.","triggerScenarios":"threat_scan_on_hit = \"block\", \"quarantine\" or \"reject-on-write\" while threat_scan is on/strict; \"block on read\" with spaces fails (only the hyphen/underscore forms pass).","commonSituations":"Guessing sibling names of documented values; config migrated from another policy schema.","solutions":["Use reject or block-on-read (block_on_read also accepted)","Choose block-on-read if writes must persist and flagged rows should be withheld at recall instead","Restart after the edit","Validate both policy enums at startup"],"exampleFix":"# before\n[memory.policy]\nthreat_scan = \"strict\"\nthreat_scan_on_hit = \"block\"\n\n# after\n[memory.policy]\nthreat_scan = \"strict\"\nthreat_scan_on_hit = \"block-on-read\"   # or \"reject\"","handlingStrategy":"validation","validationCode":"let v = cfg.memory.policy.threat_scan_on_hit.trim().to_ascii_lowercase();\nanyhow::ensure!(matches!(v.as_str(), \"reject\" | \"block-on-read\" | \"block_on_read\"), \"threat_scan_on_hit invalid: {v}\");","typeGuard":"fn is_valid_on_hit(v: &str) -> bool {\n    matches!(v.trim().to_ascii_lowercase().as_str(), \"reject\" | \"block-on-read\" | \"block_on_read\")\n}","tryCatchPattern":"if let Err(e) = memory.store(k, v).await {\n    if e.to_string().contains(\"invalid memory.policy.threat_scan_on_hit value\") { fix_config_and_restart(); }\n    return Err(e);\n}","preventionTips":["Remember the value is only parsed once threat_scan != off — test with scanning on","Accept only reject/block-on-read in config templates","Lint the pair (threat_scan, threat_scan_on_hit) together"],"tags":["configuration","policy","threat-scan","validation","rust"],"backgroundTag":"invalid-config-value","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}