{"record":{"id":"0a207b3aea8fa68d","repo":"zeroclaw-labs/zeroclaw","slug":"memory-write-blocked-by-content-scan-kinds","errorCode":null,"errorMessage":"memory write blocked by content scan: {kinds}","messagePattern":"memory write blocked by content scan: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-memory/src/scanned.rs","lineNumber":212,"sourceCode":"            if !findings.is_empty() {\n                let kinds = findings\n                    .iter()\n                    .map(|finding| finding.kind.to_string())\n                    .collect::<Vec<_>>()\n                    .join(\",\");\n                ::zeroclaw_log::record!(\n                    WARN,\n                    ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note)\n                        .with_outcome(::zeroclaw_log::EventOutcome::Failure)\n                        .with_attrs(::serde_json::json!({\n                                \"key\": key,\n                                \"namespace\": namespace,\n                                \"kinds\": kinds,\n                        })),\n                    \"memory write flagged by content scan\"\n                );\n                if matches!(on_hit, OnHit::Reject) {\n                    anyhow::bail!(\"memory write blocked by content scan: {kinds}\");\n                }\n            }\n        }\n\n        Ok(persisted)\n    }\n\n    /// Validate namespace/category policy for a write. Any violation\n    /// aborts the write.\n    async fn enforce_policy(\n        &self,\n        key: &str,\n        namespace: Option<&str>,\n        category: &MemoryCategory,\n    ) -> anyhow::Result<()> {\n        let namespace = namespace.unwrap_or(\"default\");\n        let enforcer = PolicyEnforcer::new(&self.policy);\n        if let Err(error) =","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-memory/src/scanned.rs#L194-L230","documentation":"process_content() runs threat::scan over the (post-redaction) content whenever threat_scan is on or strict. If findings exist and threat_scan_on_hit = reject, the write is aborted before reaching the backend, and the error lists the finding kinds. This is the policy working as designed (fail-closed); a WARN 'memory write flagged by content scan' is logged first.","triggerScenarios":"Storing content containing patterns the scanner flags (e.g., prompt-injection markers under strict scope) while [memory.policy] has threat_scan = on|strict and threat_scan_on_hit = \"reject\".","commonSituations":"Agents persisting scraped web pages, raw model output, or user text containing injection-style phrasing; strict mode flagging innocuous content; CI tests storing fixture text that trips the scanner.","solutions":["If the content is legitimately unsafe to persist, treat the error as final: log and drop the write — that is the policy doing its job","Switch threat_scan_on_hit to block-on-read to persist flagged rows but withhold them at recall","Pre-clean the content (strip or rewrite flagged passages) before store","Move from strict to on if strict-scope patterns are too aggressive, and report false positives"],"exampleFix":"# before\n[memory.policy]\nthreat_scan = \"strict\"\nthreat_scan_on_hit = \"reject\"\n\n# after\n[memory.policy]\nthreat_scan = \"strict\"\nthreat_scan_on_hit = \"block-on-read\"   # writes persist; flagged rows withheld at recall","handlingStrategy":"try-catch","validationCode":"// Optional pre-flight if you expose the threat module: scan before storing\n// let findings = zeroclaw_memory::threat::scan(&content, Scope::Strict);\n// if !findings.is_empty() { /* sanitize or route to a side log instead of store() */ }","typeGuard":"fn is_scan_rejected(e: &anyhow::Error) -> bool {\n    e.to_string().starts_with(\"memory write blocked by content scan\")\n}","tryCatchPattern":"match memory.store(key, content).await {\n    Err(e) if is_scan_rejected(&e) => { log_rejected(key, &e); Ok(()) } // policy win: drop write, keep agent alive\n    other => other,\n}","preventionTips":["Treat a scan rejection as expected control flow, never crash the agent on it","Pre-clean scraped/raw content before store","Choose block-on-read when persistence matters more than immediate visibility","Log the finding kinds so false positives can be reported and tuned"],"tags":["content-scanning","policy","threat-scan","security","rust"],"backgroundTag":"content-filter-rejected","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}