zeroclaw-labs/zeroclaw · error
invalid memory.policy.threat_scan_on_hit value {other:?}; ex
Error message
invalid memory.policy.threat_scan_on_hit value {other:?}; expected reject or block-on-read What it means
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.
Source
Thrown at crates/zeroclaw-memory/src/scanned.rs:105
"on" => Ok(ThreatScanMode::On),
"strict" => Ok(ThreatScanMode::Strict),
other => anyhow::bail!(
"invalid memory.policy.threat_scan value {other:?}; expected off, on, or strict"
),
}
}
fn on_hit(&self) -> anyhow::Result<OnHit> {
match self
.policy
.threat_scan_on_hit
.trim()
.to_ascii_lowercase()
.as_str()
{
"reject" => Ok(OnHit::Reject),
"block-on-read" | "block_on_read" => Ok(OnHit::BlockOnRead),
other => anyhow::bail!(
"invalid memory.policy.threat_scan_on_hit value {other:?}; expected reject or block-on-read"
),
}
}
fn scan_scope(&self) -> anyhow::Result<Option<Scope>> {
Ok(match self.scan_mode()? {
ThreatScanMode::Off => None,
ThreatScanMode::On => Some(Scope::On),
ThreatScanMode::Strict => Some(Scope::Strict),
})
}
/// Scope for read-time re-scanning; `None` disables read filtering.
fn read_scope(&self) -> anyhow::Result<Option<Scope>> {
if !self.policy.threat_scan_load_time {
return Ok(None);
}View on GitHub (pinned to 88bb9c8533)
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
Example fix
# before [memory.policy] threat_scan = "strict" threat_scan_on_hit = "block" # after [memory.policy] threat_scan = "strict" threat_scan_on_hit = "block-on-read" # or "reject"
Defensive patterns
Strategy: validation
Validate before calling
let v = cfg.memory.policy.threat_scan_on_hit.trim().to_ascii_lowercase();
anyhow::ensure!(matches!(v.as_str(), "reject" | "block-on-read" | "block_on_read"), "threat_scan_on_hit invalid: {v}"); Type guard
fn is_valid_on_hit(v: &str) -> bool {
matches!(v.trim().to_ascii_lowercase().as_str(), "reject" | "block-on-read" | "block_on_read")
} Try / catch
if let Err(e) = memory.store(k, v).await {
if e.to_string().contains("invalid memory.policy.threat_scan_on_hit value") { fix_config_and_restart(); }
return Err(e);
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: Guessing sibling names of documented values; config migrated from another policy schema.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- invalid memory.policy.threat_scan value {other:?}; expected
- invalid memory.policy.redact_categories value(s): {}; expect
- cloud_ops.iac_tools must not be empty when cloud_ops is enab
- gateway.path_prefix contains invalid character '{bad}'; only
- risk_profiles.{profile_alias}.shell_env_passthrough[{i}] is
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/8640abaefad19c3b.
Report an issue: GitHub.