zeroclaw-labs/zeroclaw · error

manifest missing [tool] description

Error message

manifest missing [tool] description

What it means

Second required-field check in `load_one_plugin`: `[tool].description` is empty after trimming. Every plugin must carry a non-empty, human-readable description because it feeds tool listings and help output, so a manifest without it is rejected with the exact field named. Parse errors were already handled separately, so this is purely a content validation failure.

Source

Thrown at crates/zeroclaw-hardware/src/loader.rs:182

        ::zeroclaw_log::record!(
            WARN,
            ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)
                .with_outcome(::zeroclaw_log::EventOutcome::Failure)
                .with_attrs(::serde_json::json!({
                    "manifest_path": manifest_path.display().to_string(),
                    "error": format!("{}", e),
                })),
            "hardware plugin manifest failed to parse"
        );
        anyhow::Error::msg(format!("TOML parse error in tool.toml: {e}"))
    })?;

    // Validate required fields — fail fast with a descriptive error.
    if manifest.tool.name.trim().is_empty() {
        anyhow::bail!("manifest missing [tool] name");
    }
    if manifest.tool.description.trim().is_empty() {
        anyhow::bail!("manifest missing [tool] description");
    }
    if manifest.exec.binary.trim().is_empty() {
        anyhow::bail!("manifest missing [exec] binary");
    }

    // Validate binary path: must exist, be a regular file, and reside within plugin_dir.
    let canonical_plugin_dir = plugin_dir.canonicalize().map_err(|e| {
        ::zeroclaw_log::record!(
            WARN,
            ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)
                .with_outcome(::zeroclaw_log::EventOutcome::Failure)
                .with_attrs(::serde_json::json!({
                    "plugin_dir": plugin_dir.display().to_string(),
                    "error": format!("{}", e),
                })),
            "cannot canonicalize plugin dir"
        );
        anyhow::Error::msg(format!(

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Add a one-line `description = "..."` under `[tool]`
  2. Ensure the value is non-empty after trimming — blank or whitespace-only strings still fail

Example fix

# before
[tool]
name = "read-sensors"
# after
[tool]
name = "read-sensors"
description = "Reads board sensors and returns JSON"
Defensive patterns

Strategy: validation

Validate before calling

fn required_fields_ok(m: &ToolManifest) -> Result<(), String> {
    if m.tool.description.trim().is_empty() {
        return Err("[tool] description is required".into());
    }
    Ok(())
}

Type guard

fn manifest_has_description(raw: &str) -> bool {
    toml::from_str::<ToolManifest>(raw)
        .map(|m| !m.tool.description.trim().is_empty())
        .unwrap_or(false)
}

Prevention

When it happens

Trigger: A `tool.toml` `[tool]` section with `name` present but `description` missing, empty, or whitespace-only.

Common situations: Minimal manifests written only to satisfy the name check; a description removed because it looked optional; leftover whitespace placeholder text.

Related errors


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