{"record":{"id":"f38b80c6997e4534","repo":"paperclipai/paperclip","slug":"invalid-skill-document","errorCode":"invalid_skill_document","errorMessage":"Provide a complete SKILL.md with name and description matching the command inputs, a nonempty body, and slug equal to name when supplied","messagePattern":"Provide a complete SKILL\\.md with name and description matching the command inputs, a nonempty body, and slug equal to name when supplied","errorType":"error_code","errorClass":"CapabilityMockControlPlaneError","httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/mock-core/capability-mock-control-plane-adapter.ts","lineNumber":721,"sourceCode":"    const entityRefs = [`task:${task.id}`];\n    const scheduledWakeIds: string[] = [];\n    switch (command.kind) {\n      case \"report_progress\": {\n        requireText(command.body, \"progress body\");\n        const comment = this.#appendComment(task.id, run.actorId, command.body);\n        entityRefs.push(`comment:${comment.id}`);\n        break;\n      }\n      case \"create_skill\": {\n        requireText(command.name, \"skill name\");\n        requireText(command.markdown, \"skill markdown\");\n        const document = parseFrontmatterMarkdown(command.markdown);\n        const validMetadata = validateSkillFrontmatter(document.frontmatter);\n        if (!document.hasFrontmatter || !validMetadata || !document.body.trim()\n          || document.frontmatter.name !== command.name\n          || document.frontmatter.description !== command.description.trim()\n          || (command.slug !== undefined && command.slug !== command.name)) {\n          throw new CapabilityMockControlPlaneError(\n            \"invalid_skill_document\",\n            \"Provide a complete SKILL.md with name and description matching the command inputs, a nonempty body, and slug equal to name when supplied\",\n          );\n        }\n        const slug = command.slug ?? command.name;\n        const skills = this.#state.skills ??= [];\n        if (skills.some(skill => skill.companyId === run.companyId && skill.slug === slug)) {\n          throw new CapabilityMockControlPlaneError(\"fixture_state_invalid\", \"A skill with that name already exists\");\n        }\n        const skill = { id: this.#id(\"skill\"), companyId: run.companyId, name: command.name,\n          slug, description: command.description.trim(), markdown: command.markdown, versionId: this.#id(\"skill-version\") };\n        skills.push(skill);\n        entityRefs.push(`skill:${skill.id}`);\n        break;\n      }\n      case \"write_document\": {\n        requireText(command.key, \"document key\");\n        requireText(command.title, \"document title\");","sourceCodeStart":703,"sourceCodeEnd":739,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/packages/paperclip-runner/src/mock-core/capability-mock-control-plane-adapter.ts#L703-L739","documentation":"CapabilityMockControlPlaneError with code `invalid_skill_document`, thrown when a create_skill command's markdown does not form a valid SKILL.md. The adapter requires YAML frontmatter that passes validateSkillFrontmatter, frontmatter name equal to command.name, description equal to the trimmed command.description, a nonempty body, and — if slug is supplied — slug equal to name. This guards fixture/mock skill creation against half-written documents.","triggerScenarios":"applyCommand → #executeCommand for a create_skill command where: markdown has no frontmatter; frontmatter fails validateSkillFrontmatter (missing name/description or bad format); body is whitespace-only; frontmatter.name differs from command.name; frontmatter.description differs from command.description.trim(); or command.slug is set and differs from command.name.","commonSituations":"Fixture authors writing SKILL.md markdown without the --- frontmatter block; editing the description in the command but not in the frontmatter; supplying a slug that is not the slugified name; empty or placeholder body text.","solutions":["Add valid YAML frontmatter with `name` and `description` fields that pass validateSkillFrontmatter","Make frontmatter.name exactly equal command.name and frontmatter.description exactly equal command.description.trim()","Ensure the markdown body after frontmatter is nonempty","Omit `slug` (it defaults to name) or set it exactly equal to command.name"],"exampleFix":"// before\ncreateSkill({ name: \"my-skill\", description: \"Does things\", markdown: \"Just a body\", slug: \"other\" })\n// after\nconst markdown = \"---\\nname: my-skill\\ndescription: Does things\\n---\\n\\nDoes things when needed.\";\ncreateSkill({ name: \"my-skill\", description: \"Does things\", markdown }) // no slug, or slug: \"my-skill\"","handlingStrategy":"validation","validationCode":"const doc = parseFrontmatterMarkdown(markdown);\nconst meta = validateSkillFrontmatter(doc.frontmatter);\nconst valid = doc.hasFrontmatter && !!meta && doc.body.trim().length > 0\n  && doc.frontmatter.name === name\n  && doc.frontmatter.description === description.trim()\n  && (slug === undefined || slug === name);\nif (!valid) throw new Error(\"invalid_skill_document\");","typeGuard":"function isValidSkillDoc(doc, cmd) {\n  return doc.hasFrontmatter\n    && typeof doc.frontmatter?.name === \"string\"\n    && doc.frontmatter.name === cmd.name\n    && doc.frontmatter.description === cmd.description.trim()\n    && doc.body.trim() !== \"\"\n    && (cmd.slug === undefined || cmd.slug === cmd.name);\n}","tryCatchPattern":"try {\n  await adapter.applyCommand(createSkillCmd);\n} catch (e) {\n  if (e instanceof CapabilityMockControlPlaneError && e.code === \"invalid_skill_document\") {\n    // fix markdown frontmatter/body and retry\n  } else throw e;\n}","preventionTips":["Generate SKILL.md markdown from a template that emits frontmatter from name/description","Trim descriptions once and reuse the same string in frontmatter and command","Never pass a slug different from name","Assert the body is nonempty in fixture builders"],"tags":["skills","validation","mock","frontmatter"],"backgroundTag":"schema-validation-failed","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}