zeroclaw-labs/zeroclaw · error

event '{kind}' is invalid; expected created, modified, delet

Error message

event '{kind}' is invalid; expected created, modified, deleted, or renamed

What it means

The filesystem listener only emits four event kinds — `created`, `modified`, `deleted`, `renamed` — and `validate` checks each `events` entry against exactly those strings. Anything else (including near-synonyms like `create` or `write`) is rejected so the watcher's event mapping never receives an unknown kind.

Source

Thrown at crates/zeroclaw-config/src/schema.rs:16438

    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(())
    }
}

impl ChannelConfig for FilesystemConfig {
    fn name() -> &'static str {
        "Filesystem"
    }
    fn desc() -> &'static str {
        "Filesystem SOP Listener"
    }
}

fn default_filesystem_events() -> Vec<String> {

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Use only `created`, `modified`, `deleted`, `renamed` (all four are the default when `events` is omitted).
  2. Copy the default list and delete the kinds you do not want.
  3. Check for case differences and typos in each entry.

Example fix

# before
events = ["create", "write", "delete"]

# after
events = ["created", "modified", "deleted"]
Defensive patterns

Strategy: type-guard

Validate before calling

const FS_EVENTS: [&str; 4] = ["created", "modified", "deleted", "renamed"];
anyhow::ensure!(
    cfg.events.iter().all(|k| FS_EVENTS.contains(&k.as_str())),
    "invalid filesystem event kind"
);

Type guard

fn is_valid_fs_event(kind: &str) -> bool {
    matches!(kind, "created" | "modified" | "deleted" | "renamed")
}

Prevention

When it happens

Trigger: `events = ["create", "write"]` (inotify-style names); `events = ["Created"]` (wrong case); a typo like `modifed`; entries appended from a documentation example for a different watcher library.

Common situations: Porting config from inotifywait/fsnotify vocabulary where `create`/`write` are the norm; assuming past-tense vs present-tense does not matter; hand-typing the list instead of copying the default.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/87a792b7bae4f523. Report an issue: GitHub.