{"record":{"id":"49892e94196ea6e1","repo":"github/spec-kit","slug":"requires-must-be-a-mapping-when-present","errorCode":null,"errorMessage":"'requires' must be a mapping when present.","messagePattern":"'requires' must be a mapping when present\\.","errorType":"exception","errorClass":"BundlerError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/bundler/models/manifest.py","lineNumber":118,"sourceCode":"\n        bundle_raw = data.get(\"bundle\")\n        if not isinstance(bundle_raw, dict):\n            raise BundlerError(\"Manifest is missing the required 'bundle' mapping.\")\n        meta = BundleMeta(\n            id=_text(bundle_raw.get(\"id\")),\n            name=_text(bundle_raw.get(\"name\")),\n            version=_text(bundle_raw.get(\"version\")),\n            role=_text(bundle_raw.get(\"role\")),\n            description=_text(bundle_raw.get(\"description\")),\n            author=_text(bundle_raw.get(\"author\")),\n            license=_text(bundle_raw.get(\"license\")),\n        )\n\n        requires_raw = data.get(\"requires\")\n        if requires_raw is None:\n            requires_raw = {}\n        elif not isinstance(requires_raw, dict):\n            raise BundlerError(\"'requires' must be a mapping when present.\")\n        requires = Requires(\n            speckit_version=_text(requires_raw.get(\"speckit_version\")),\n            tools=_parse_str_list(requires_raw.get(\"tools\"), \"requires.tools\"),\n            mcp=_parse_str_list(requires_raw.get(\"mcp\"), \"requires.mcp\"),\n        )\n\n        integration = None\n        integration_raw = data.get(\"integration\")\n        # Mirror the requires/provides guards above: a present-but-non-mapping\n        # 'integration' (e.g. a bare string \"copilot\") was silently dropped,\n        # leaving the bundle wrongly integration-agnostic. Reject it instead.\n        if integration_raw is not None and not isinstance(integration_raw, dict):\n            raise BundlerError(\"'integration' must be a mapping when present.\")\n        if isinstance(integration_raw, dict) and integration_raw.get(\"id\"):\n            integration = IntegrationRef(id=str(integration_raw[\"id\"]).strip())\n\n        provides = data.get(\"provides\")\n        if provides is None:","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/bundler/models/manifest.py#L100-L136","documentation":"Raised by BundleManifest.from_dict when the manifest's optional 'requires' key is present but is not a YAML mapping. 'requires' holds speckit_version, tools, and mcp; a null/absent value defaults to empty, but any other type (string, list, scalar) is rejected instead of being silently mis-read.","triggerScenarios":"A manifest contains 'requires: \"^1.0\"' or 'requires: [git]' (string/list) instead of a mapping like 'requires: {speckit_version: ...}'. Any parse of that manifest via BundleManifest.from_dict raises.","commonSituations":"Writing the version constraint directly under 'requires:' instead of 'requires: speckit_version:'; confusing the manifest schema with package.json-style requirements; hand-authoring a first bundle.","solutions":["Rewrite 'requires' as a mapping with the supported keys: speckit_version, tools, mcp.","Remove the 'requires' key entirely if there are no requirements — absence is valid."],"exampleFix":"# before (bundle.yml)\nrequires: \"2.0\"\n\n# after\nrequires:\n  speckit_version: \"2.0\"\n  tools:\n    - git","handlingStrategy":"type-guard","validationCode":"def requires_shape_ok(data: dict) -> bool:\n    r = data.get(\"requires\")\n    return r is None or isinstance(r, dict)","typeGuard":"def is_requires_mapping(raw: object) -> bool:\n    return raw is None or isinstance(raw, dict)","tryCatchPattern":"try:\n    manifest = BundleManifest.from_file(p)\nexcept BundlerError as e:\n    if \"'requires' must be a mapping\" in str(e):\n        # rewrite as requires: {speckit_version: ...} or drop the key\n        ...","preventionTips":["'requires' is a mapping of speckit_version/tools/mcp — not a constraint string.","Omit 'requires' entirely when there are no requirements."],"tags":["bundler","manifest","yaml","validation"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}