{"record":{"id":"158265ea070d1a81","repo":"conductor-oss/conductor","slug":"skill-md-frontmatter-must-be-a-mapping","errorCode":null,"errorMessage":"SKILL.md frontmatter must be a mapping","messagePattern":"SKILL\\.md frontmatter must be a mapping","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"agentspan/src/main/java/org/conductoross/conductor/ai/agentspan/runtime/service/SkillRegistryService.java","lineNumber":577,"sourceCode":"            out.write(buffer, 0, read);\n        }\n        return out.toByteArray();\n    }\n\n    private Map<String, Object> parseSkillFrontmatter(String skillMd) {\n        Matcher matcher = FRONTMATTER_PATTERN.matcher(skillMd);\n        if (!matcher.matches()) {\n            throw new IllegalArgumentException(\"SKILL.md is missing required YAML frontmatter\");\n        }\n        try {\n            LoaderOptions options = new LoaderOptions();\n            Yaml yaml = new Yaml(new SafeConstructor(options));\n            Object value = yaml.load(matcher.group(1));\n            if (value == null) {\n                return Map.of();\n            }\n            if (!(value instanceof Map<?, ?> map)) {\n                throw new IllegalArgumentException(\"SKILL.md frontmatter must be a mapping\");\n            }\n            return MAPPER.convertValue(map, MAP_TYPE);\n        } catch (IllegalArgumentException e) {\n            throw e;\n        } catch (Exception e) {\n            throw new IllegalArgumentException(\n                    \"Invalid SKILL.md frontmatter: \" + e.getMessage(), e);\n        }\n    }\n\n    private String decodeUtf8(String path, byte[] data) {\n        try {\n            return StandardCharsets.UTF_8\n                    .newDecoder()\n                    .onMalformedInput(CodingErrorAction.REPORT)\n                    .onUnmappableCharacter(CodingErrorAction.REPORT)\n                    .decode(ByteBuffer.wrap(data))\n                    .toString();","sourceCodeStart":559,"sourceCodeEnd":595,"githubUrl":"https://github.com/conductor-oss/conductor/blob/cf7c3e4a8adfb158be778ab1ec525323c363cd3a/agentspan/src/main/java/org/conductoross/conductor/ai/agentspan/runtime/service/SkillRegistryService.java#L559-L595","documentation":"Thrown by SkillRegistryService when the YAML frontmatter of a SKILL.md file parses successfully but is not a key/value mapping (e.g. it is a bare list or scalar). The loader uses SnakeYAML's SafeConstructor, so a top-level YAML scalar like `hello` or a `- item` list yields a String/ArrayList rather than a Map, which this branch rejects. The check exists because the rest of the registry assumes structured metadata keyed by field name.","triggerScenarios":"Uploading/parsing a SKILL.md whose frontmatter between the `---` fences is a YAML list (`- name: x`) or a bare scalar (`just a string`). The FRONTMATTER_PATTERN matches, yaml.load() returns a non-Map, and the `instanceof Map<?,?>` guard fails.","commonSituations":"Author copy-pastes a list-style YAML config into frontmatter; a generator emits array metadata; frontmatter was hand-edited and demoted from `name: foo` to `- name: foo`.","solutions":["Open the offending SKILL.md and rewrite the frontmatter as a mapping: each field on its own line as `key: value`.","Validate the YAML parses to an object before upload using `yq '. | type' SKILL.md` or a local SnakeYAML load.","Ensure there is exactly one document and it starts with a key, not a `-`."],"exampleFix":"// before (SKILL.md frontmatter)\n---\n- name: my-skill\n  version: 1.0.0\n---\n// after\n---\nname: my-skill\nversion: 1.0.0\n---","handlingStrategy":"validation","validationCode":"// Validate SKILL.md frontmatter is a mapping before publishing.\nprivate static void assertFrontmatterIsMap(String skillMd) {\n    Matcher m = FRONTMATTER_PATTERN.matcher(skillMd);\n    if (!m.matches()) throw new IllegalArgumentException(\"missing frontmatter\");\n    Object parsed = new Yaml(new SafeConstructor(new LoaderOptions())).load(m.group(1));\n    if (parsed != null && !(parsed instanceof Map<?, ?>)) {\n        throw new IllegalArgumentException(\n            \"frontmatter is \" + parsed.getClass().getSimpleName() + \", must be a mapping\");\n    }\n}","typeGuard":"boolean isFrontmatterMap(String skillMd) {\n    Matcher m = FRONTMATTER_PATTERN.matcher(skillMd);\n    if (!m.matches()) return false;\n    Object v = new Yaml(new SafeConstructor(new LoaderOptions())).load(m.group(1));\n    return v == null || v instanceof Map<?, ?>;\n}","tryCatchPattern":"try {\n    Map<String,Object> fm = skillRegistry.parseFrontmatter(skillMd);\n} catch (IllegalArgumentException e) {\n    // surface the message to the author; do not retry\n    return badRequest(e.getMessage());\n}","preventionTips":["Always author SKILL.md frontmatter as `key: value` pairs, never a list or scalar.","Run `yq '. | type' SKILL.md` in CI and fail if the type is not `!!map`.","Use a JSON-schema-validated manifest tool instead of hand-writing YAML."],"tags":["skill-registry","yaml","frontmatter","validation"],"backgroundTag":null,"analyzedSha":"cf7c3e4a8adfb158be778ab1ec525323c363cd3a","analyzedAt":"2026-08-14T03:33:19.897Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}