{"record":{"id":"d8f626f19db855ad","repo":"zeroclaw-labs/zeroclaw","slug":"skill-content-is-empty","errorCode":null,"errorMessage":"Skill content is empty","messagePattern":"Skill content is empty","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-runtime/src/skills/improver.rs","lineNumber":136,"sourceCode":"                    md_path.display()\n                )\n            })?;\n\n        self.cooldowns.insert(slug.to_string(), Instant::now());\n\n        Ok(Some(slug.to_string()))\n    }\n\n    fn skills_dir(&self) -> PathBuf {\n        self.workspace_dir.join(\"skills\")\n    }\n}\n\n/// Validate skill content: must be non-empty, have a parseable YAML front-matter\n/// block with a non-empty `name` field.\npub fn validate_skill_content(content: &str) -> Result<()> {\n    if content.trim().is_empty() {\n        bail!(\"Skill content is empty\");\n    }\n\n    let Some((front, _body)) = split_front_matter(content) else {\n        bail!(\"Skill content is missing YAML front-matter (expected `---` delimited block at top)\");\n    };\n\n    let name = front_matter_value(&front, \"name\").unwrap_or_default();\n    if name.trim().is_empty() {\n        bail!(\"Skill front-matter missing required `name` field\");\n    }\n\n    Ok(())\n}\n\n/// Split a SKILL.md into (front_matter_text, body_text).\n/// Returns `None` if the file doesn't start with `---\\n` or has no closing\n/// `---` delimiter.\nfn split_front_matter(content: &str) -> Option<(String, String)> {","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/skills/improver.rs#L118-L154","documentation":"Thrown by validate_skill_content (crates/zeroclaw-runtime/src/skills/improver.rs) when the skill content handed to SkillImprover::improve_skill is empty or whitespace-only. The improver refuses to write blank content because an atomic rename of empty text would erase the existing SKILL.md. It fires on the incoming improved_content argument, and again on the temp file after write as a self-check.","triggerScenarios":"Calling improve_skill(slug, \"\", reason) or with content containing only whitespace/newlines. Passing through an LLM completion that came back empty (truncation, content filter, mis-parsed streaming chunk) without checking it.","commonSituations":"Self-improvement pipelines where the provider returns an empty message; an upstream bug that reads the wrong file into improved_content; a generation step that returns Ok(String::new()) on soft failure.","solutions":["Check improved_content.trim().is_empty() before calling improve_skill; skip or re-request the generation when empty","If content comes from an LLM, retry the generation and require a non-empty completion before improving","Log the slug and the raw provider response so empty generations are visible in telemetry","If the message is prefixed 'Validation failed after write', the temp-file self-check failed: inspect what wrote .SKILL.md.tmp in your workspace skills dir"],"exampleFix":"// before\nimprover.improve_skill(slug, improved_content, reason).await?; // fails on empty LLM output\n\n// after\nif improved_content.trim().is_empty() {\n    tracing::warn!(slug, \"empty improvement content; skipping\");\n    return Ok(None);\n}\nimprover.improve_skill(slug, improved_content, reason).await?;","handlingStrategy":"validation","validationCode":"// Before calling improve_skill:\nif improved_content.trim().is_empty() {\n    tracing::warn!(slug, \"empty improvement content; skipping\");\n    return Ok(None);\n}\nimprover.improve_skill(slug, improved_content, reason).await?;","typeGuard":"fn has_skill_body(content: &str) -> bool {\n    !content.trim().is_empty()\n}","tryCatchPattern":null,"preventionTips":["Never pass provider output to improve_skill unchecked; require a non-empty completion","Treat empty LLM generations as a skip, not an error, in improvement loops","Log slug + content length before every improvement so blanks are traceable"],"tags":["skills","skill-improver","validation","empty-input"],"backgroundTag":"empty-required-input","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}