zeroclaw-labs/zeroclaw · error
memory write denied by policy: {error}
Error message
memory write denied by policy: {error} What it means
After content screening, enforce_policy() runs policy_gate::validate_store with a PolicyEnforcer built from [memory.policy] (namespace/category rules). Any violation aborts the write; the inner {error} text names the exact rule that failed. Fail-closed by design — every store* variant routes through this check.
Source
Thrown at crates/zeroclaw-memory/src/scanned.rs:244
category: &MemoryCategory,
) -> anyhow::Result<()> {
let namespace = namespace.unwrap_or("default");
let enforcer = PolicyEnforcer::new(&self.policy);
if let Err(error) =
crate::policy_gate::validate_store(&self.inner, &enforcer, namespace, category).await
{
::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,
"error": error.to_string(),
})),
"memory write denied by policy"
);
anyhow::bail!("memory write denied by policy: {error}");
}
Ok(())
}
/// Re-scan one recalled entry; `true` means the entry passes.
fn entry_passes_read_scan(&self, entry: &MemoryEntry, scope: Scope) -> bool {
let findings = threat::scan(&entry.content, scope);
if findings.is_empty() {
return true;
}
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)View on GitHub (pinned to 88bb9c8533)
Solutions
- Read the inner error text — it names the violated rule (disallowed namespace, disallowed category, or a limit)
- Write to a namespace/category permitted by [memory.policy], or extend the policy rules
- If a per-namespace limit tripped, forget old entries or raise the limit
- Restart after policy edits so ScannedMemory picks up the new policy
Defensive patterns
Strategy: validation
Validate before calling
// Mirror [memory.policy] rules at the call site: refuse locally before the doomed write
fn policy_allows(policy: &MemoryPolicyConfig, namespace: &str, category: &MemoryCategory) -> bool {
// replicate the namespace/category allow rules and limits you configured
true
}
anyhow::ensure!(policy_allows(&cfg.memory.policy, ns, &cat), "write to {ns} will be denied by policy"); Type guard
fn is_policy_denied(e: &anyhow::Error) -> bool {
e.to_string().starts_with("memory write denied by policy")
} Try / catch
match memory.store(k, v).await {
Err(e) if is_policy_denied(&e) => { notify_owner_of_rule(&e); Ok(()) } // the inner text names the violated rule
other => other,
} Prevention
- Keep [memory.policy] namespace/category rules in sync with every writing call site
- Surface the inner rule text to users so they can self-correct the namespace
- Watch per-namespace limits during bulk imports
- Restart after policy edits; the decorator clones policy at construction
When it happens
Trigger: Storing into a namespace or category that [memory.policy] disallows (allow/deny rules, per-namespace limits such as max entries); all store, store_with_metadata, store_with_options and store_with_agent calls are gated.
Common situations: Tightening policy in config and forgetting call sites that write to now-restricted namespaces; new categories missing from the policy allowlist; bulk imports tripping per-namespace quotas.
Related errors
- memory consolidation write denied by policy: {e}
- memory fact write denied by policy: {e}
- Qdrant requires non-zero dimensional embeddings
- invalid memory.policy.threat_scan value {other:?}; expected
- invalid memory.policy.threat_scan_on_hit value {other:?}; ex
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/42f211f60dc53932.
Report an issue: GitHub.