zeroclaw-labs/zeroclaw · error
memory write blocked by content scan: {kinds}
Error message
memory write blocked by content scan: {kinds} What it means
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.
Source
Thrown at crates/zeroclaw-memory/src/scanned.rs:212
if !findings.is_empty() {
let kinds = findings
.iter()
.map(|finding| finding.kind.to_string())
.collect::<Vec<_>>()
.join(",");
::zeroclaw_log::record!(
WARN,
::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note)
.with_outcome(::zeroclaw_log::EventOutcome::Failure)
.with_attrs(::serde_json::json!({
"key": key,
"namespace": namespace,
"kinds": kinds,
})),
"memory write flagged by content scan"
);
if matches!(on_hit, OnHit::Reject) {
anyhow::bail!("memory write blocked by content scan: {kinds}");
}
}
}
Ok(persisted)
}
/// Validate namespace/category policy for a write. Any violation
/// aborts the write.
async fn enforce_policy(
&self,
key: &str,
namespace: Option<&str>,
category: &MemoryCategory,
) -> anyhow::Result<()> {
let namespace = namespace.unwrap_or("default");
let enforcer = PolicyEnforcer::new(&self.policy);
if let Err(error) =View on GitHub (pinned to 88bb9c8533)
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
Example fix
# before [memory.policy] threat_scan = "strict" threat_scan_on_hit = "reject" # after [memory.policy] threat_scan = "strict" threat_scan_on_hit = "block-on-read" # writes persist; flagged rows withheld at recall
Defensive patterns
Strategy: try-catch
Validate before calling
// Optional pre-flight if you expose the threat module: scan before storing
// let findings = zeroclaw_memory::threat::scan(&content, Scope::Strict);
// if !findings.is_empty() { /* sanitize or route to a side log instead of store() */ } Type guard
fn is_scan_rejected(e: &anyhow::Error) -> bool {
e.to_string().starts_with("memory write blocked by content scan")
} Try / catch
match memory.store(key, content).await {
Err(e) if is_scan_rejected(&e) => { log_rejected(key, &e); Ok(()) } // policy win: drop write, keep agent alive
other => other,
} Prevention
- 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
When it happens
Trigger: 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".
Common situations: 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.
Related errors
- invalid memory.policy.threat_scan value {other:?}; expected
- invalid memory.policy.threat_scan_on_hit value {other:?}; ex
- security.otp.cache_valid_secs must be greater than or equal
- security.otp.gated_actions[{i}] contains invalid characters:
- AgentScopedMemory refuses purge_namespace: cross-agent bulk
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/0a207b3aea8fa68d.
Report an issue: GitHub.