{"record":{"id":"4b514159012edef8","repo":"mastra-ai/mastra","slug":"skill-md-not-found-in-skill-files","errorCode":null,"errorMessage":"SKILL.md not found in skill files","messagePattern":"SKILL\\.md not found in skill files","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/workspace/skills/publish.ts","lineNumber":226,"sourceCode":" * Parse a flat array of skill files into a denormalized snapshot.\n *\n * Finds `SKILL.md`, parses its YAML frontmatter into structured fields\n * (name, description, license, compatibility, metadata), and uses the\n * markdown body as `instructions`. Discovers `references/`, `scripts/`,\n * and `assets/` subdirectory paths from the file list.\n *\n * Used by both the publish flow (which has files from a SkillSource walk)\n * and the registry install flow (which has files fetched from an external\n * registry like skills.sh). The Agent Skills spec puts metadata in\n * frontmatter and agent-facing prose in the body — this helper enforces\n * that split so frontmatter never leaks into the runtime instructions.\n *\n * @throws if `SKILL.md` is missing from the file list\n */\nexport function parseSkillSnapshotFromFiles(files: SkillSnapshotFile[]): Omit<StorageSkillSnapshotType, 'tree'> {\n  const skillMdFile = files.find(f => f.path === 'SKILL.md');\n  if (!skillMdFile) {\n    throw new Error('SKILL.md not found in skill files');\n  }\n\n  const skillMdContent =\n    typeof skillMdFile.content === 'string' ? skillMdFile.content : skillMdFile.content.toString('utf-8');\n  const parsed = matter(skillMdContent);\n  const frontmatter = parsed.data;\n  const instructions = parsed.content.trim();\n\n  const allPaths = files.map(f => f.path);\n  const references = collectSubdirPaths(allPaths, 'references');\n  const scripts = collectSubdirPaths(allPaths, 'scripts');\n  const assets = collectSubdirPaths(allPaths, 'assets');\n\n  return {\n    name: frontmatter.name,\n    description: frontmatter.description,\n    instructions,\n    license: frontmatter.license,","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/workspace/skills/publish.ts#L208-L244","documentation":"parseSkillSnapshotFromFiles builds a publishable skill snapshot from a collected file list and requires a file at path 'SKILL.md' to parse frontmatter and metadata from. If the file list contains no entry with exactly that path, publishing cannot proceed and this error is thrown. It is wrapped by collectSkillForPublish to add the skill path context (see error 2064).","triggerScenarios":"Calling parseSkillSnapshotFromFiles with a SkillSnapshotFile[] that lacks an entry with path === 'SKILL.md' — e.g. files gathered from a directory that only has supporting assets, or the file was named 'skill.md' (case mismatch) or nested ('docs/SKILL.md').","commonSituations":"A skill folder missing its SKILL.md manifest; case-sensitive filesystem vs. lowercase filename; the collect step filtered out SKILL.md; hand-building the file list for tests and forgetting the manifest.","solutions":["Ensure the skill directory contains a file at its root named exactly 'SKILL.md' (case-sensitive).","If calling parseSkillSnapshotFromFiles directly, prepend { path: 'SKILL.md', content: ... } to the files array.","Check the file collection logic isn't excluding SKILL.md via ignore/glob filters.","Catch this error in callers and surface which directory was scanned."],"exampleFix":"// before\nconst snapshot = parseSkillSnapshotFromFiles([{ path: 'skill.md', content }]);\n// after\nconst snapshot = parseSkillSnapshotFromFiles([{ path: 'SKILL.md', content }]);","handlingStrategy":"validation","validationCode":"const hasSkillMd = files.some(f => f.path === 'SKILL.md');\nif (!hasSkillMd) {\n  throw new Error(`Cannot parse snapshot: files must include 'SKILL.md' (got: ${files.map(f => f.path).join(', ')})`);\n}","typeGuard":"function hasSkillMd(files: SkillSnapshotFile[]): files is [SkillSnapshotFile, ...SkillSnapshotFile[]] & { 0: { path: 'SKILL.md' } } {\n  return files.some(f => f.path === 'SKILL.md');\n}","tryCatchPattern":"try {\n  return parseSkillSnapshotFromFiles(files);\n} catch (err) {\n  if (err instanceof Error && err.message === 'SKILL.md not found in skill files') {\n    // report which directory/file list was scanned\n  }\n  throw err;\n}","preventionTips":["Every skill directory must contain a root-level, exactly-cased 'SKILL.md'.","Check glob/ignore filters don't exclude SKILL.md.","Validate the file list before parsing in publish pipelines."],"tags":["skills","publishing","validation","missing-file"],"backgroundTag":"missing-required-file","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}