zeroclaw-labs/zeroclaw · error
path '{path}' is a broad system root; set allow_broad_roots
Error message
path '{path}' is a broad system root; set allow_broad_roots = true to watch it What it means
`FilesystemConfig` denies watching broad system roots (`/`, `/home`, `/etc`, `/var`, `/proc`, `/sys`, `/dev`, `/tmp`) unless `allow_broad_roots = true`. Trailing slashes are normalized before the check, so `/home/` still matches. The guard exists because pseudo-filesystems like `/proc` and `/sys` flood the watcher with kernel-object events and can leak system paths into SOP payloads.
Source
Thrown at crates/zeroclaw-config/src/schema.rs:16428
}
}
}
const FILESYSTEM_BROAD_ROOTS: [&str; 8] = [
"/", "/home", "/etc", "/var", "/proc", "/sys", "/dev", "/tmp",
];
impl FilesystemConfig {
/// Validate the filesystem listener configuration.
pub fn validate(&self) -> anyhow::Result<()> {
if self.paths.is_empty() {
anyhow::bail!("at least one path must be configured");
}
for path in &self.paths {
let trimmed = path.trim_end_matches('/');
let normalized = if trimmed.is_empty() { "/" } else { trimmed };
if !self.allow_broad_roots && FILESYSTEM_BROAD_ROOTS.contains(&normalized) {
anyhow::bail!(
"path '{path}' is a broad system root; set allow_broad_roots = true to watch it"
);
}
}
for kind in &self.events {
if !matches!(
kind.as_str(),
"created" | "modified" | "deleted" | "renamed"
) {
anyhow::bail!(
"event '{kind}' is invalid; expected created, modified, deleted, or renamed"
);
}
}
Ok(())
}
}
View on GitHub (pinned to 88bb9c8533)
Solutions
- Narrow the path below the broad root, e.g. `/tmp/zeroclaw-watch` or `/home/user/project`.
- If you truly need the broad root, set `allow_broad_roots = true` and accept the event-volume and payload-exposure risk, ideally pairing it with include/exclude filters.
- For `/proc` and `/sys` specifically, prefer a targeted path or a different mechanism — they are near-unwatchable at volume.
Example fix
# before paths = ["/tmp"] # after paths = ["/tmp/zeroclaw-watch"]
Defensive patterns
Strategy: validation
Validate before calling
const BROAD: [&str; 8] = ["/", "/home", "/etc", "/var", "/proc", "/sys", "/dev", "/tmp"];
let norm = |p: &str| {
let t = p.trim_end_matches('/');
if t.is_empty() { "/" } else { t }
};
anyhow::ensure!(
cfg.allow_broad_roots || cfg.paths.iter().all(|p| !BROAD.contains(&norm(p))),
"broad root watch requires allow_broad_roots = true"
); Type guard
fn is_broad_root(path: &str) -> bool {
let t = path.trim_end_matches('/');
let n = if t.is_empty() { "/" } else { t };
["/", "/home", "/etc", "/var", "/proc", "/sys", "/dev", "/tmp"].contains(&n)
} Prevention
- Default to the narrowest directory that covers the need.
- Treat allow_broad_roots = true as a deliberate, reviewed decision — pair it with include/exclude filters.
- Remember trailing slashes are normalized: /tmp/ is still /tmp.
When it happens
Trigger: `paths = ["/tmp"]` or `paths = ["/"]` with `allow_broad_roots` unset (defaults false); `paths = ["/home/"]` (trailing slash trimmed, still denied); pasting a log-watching example that tails `/var`.
Common situations: Quick experiments that watch `/tmp` for scratch files; assuming `/home` is fine because it only contains user data; migrating from a simple inotify script that watched `/` without issues on tiny systems.
Related errors
- at least one path must be configured
- event '{kind}' is invalid; expected created, modified, delet
- {entry_path}.tool must be a non-empty exact tool name withou
- qos must be 0, 1, or 2, got {}
- broker_url must start with 'mqtt://' or 'mqtts://', got: {}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/e85ddcc2672cc386.
Report an issue: GitHub.