{"record":{"id":"f7174a60dc1a4789","repo":"Yeachan-Heo/oh-my-codex","slug":"filepath-frontmatter-key-must-not-be-empty","errorCode":null,"errorMessage":"${filePath} frontmatter \"${key}\" must not be empty","messagePattern":"(.+?) frontmatter \"(.+?)\" must not be empty","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/cli/setup.ts","lineNumber":2215,"sourceCode":"\t\treadFile(src, \"utf-8\"),\n\t\treadFile(dst, \"utf-8\"),\n\t]);\n\treturn srcContent !== dstContent;\n}\n\nfunction containsTomlKey(content: string, key: string): boolean {\n\tconst escapedKey = key.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n\treturn new RegExp(`^\\\\s*${escapedKey}\\\\s*=`, \"m\").test(content);\n}\n\nfunction parseSkillFrontmatterScalar(\n\tvalue: string,\n\tkey: string,\n\tfilePath: string,\n): string {\n\tconst trimmed = value.trim();\n\tif (!trimmed) {\n\t\tthrow new Error(`${filePath} frontmatter \"${key}\" must not be empty`);\n\t}\n\tif (trimmed === \"|\" || trimmed === \">\") {\n\t\tthrow new Error(\n\t\t\t`${filePath} frontmatter \"${key}\" must be a single-line string`,\n\t\t);\n\t}\n\n\tconst quote = trimmed[0];\n\tif (quote === '\"' || quote === \"'\") {\n\t\tif (trimmed.length < 2 || trimmed.at(-1) !== quote) {\n\t\t\tthrow new Error(\n\t\t\t\t`${filePath} frontmatter \"${key}\" has an unterminated quoted string`,\n\t\t\t);\n\t\t}\n\t\tconst unquoted = trimmed.slice(1, -1).trim();\n\t\tif (!unquoted) {\n\t\t\tthrow new Error(`${filePath} frontmatter \"${key}\" must not be empty`);\n\t\t}","sourceCodeStart":2197,"sourceCodeEnd":2233,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/cli/setup.ts#L2197-L2233","documentation":"When parsing SKILL.md YAML frontmatter, a scalar value that trims to an empty string is rejected. This variant fires for the top-level trim: the raw frontmatter value contained only whitespace (or was empty after the colon).","triggerScenarios":"A frontmatter line like 'name:' or 'description:   ' where the value side contains nothing but whitespace.","commonSituations":"Hand-authored SKILL.md files with a forgotten value, template placeholders deleted, or copy-paste leaving empty keys.","solutions":["Open the SKILL.md named in the message and fill in a non-empty value for the flagged key","Use a YAML linter or the library's parseSkillFrontmatter in CI to catch this early","Keep name and description on one line: 'name: my-skill'"],"exampleFix":"# before\n---\nname:\ndescription: does things\n---\n# after\n---\nname: my-skill\ndescription: does things\n---","handlingStrategy":"validation","validationCode":"const fm = parseSkillFrontmatter(content, \"SKILL.md\"); // throws early with a precise message\nconst hasValue = (v?: string) => !!v && v.trim().length > 0;\nif (!hasValue(fm.name) || !hasValue(fm.description)) throw new Error(\"empty frontmatter field\");","typeGuard":"const nonEmpty = (v: string | undefined): v is string =>\n  typeof v === \"string\" && v.trim().length > 0;","tryCatchPattern":"try { parseSkillFrontmatter(content); } catch (e) { if (e instanceof Error && e.message.includes(\"must not be empty\")) { /* highlight the flagged key in the editor */ } else throw e; }","preventionTips":["Fill every frontmatter key with real content","Lint SKILL.md files in CI using parseSkillFrontmatter","Use skill templates with required fields pre-filled"],"tags":["yaml","frontmatter","skill","validation"],"backgroundTag":"config-validation-failed","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}