{"record":{"id":"74c02ad0bf57509e","repo":"github/spec-kit","slug":"hook-hook-name-has-invalid-priority-must-be-74c02a","errorCode":null,"errorMessage":"Hook '{hook_name}' has invalid 'priority': must be >= 1","messagePattern":"Hook '(.+?)' has invalid 'priority': must be >= 1","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/extensions/__init__.py","lineNumber":436,"sourceCode":"                for entry in coerce_hook_entries(hook_config):\n                    if not isinstance(entry, dict):\n                        raise ValidationError(\n                            f\"Invalid hook '{hook_name}': \"\n                            \"expected a mapping or list of mappings\"\n                        )\n                    if not entry.get(\"command\"):\n                        raise ValidationError(\n                            f\"Hook '{hook_name}' missing required 'command' field\"\n                        )\n                    if \"priority\" in entry:\n                        priority = entry[\"priority\"]\n                        if not isinstance(priority, int) or isinstance(priority, bool):\n                            raise ValidationError(\n                                f\"Hook '{hook_name}' has invalid 'priority': \"\n                                \"must be an integer\"\n                            )\n                        if priority < 1:\n                            raise ValidationError(\n                                f\"Hook '{hook_name}' has invalid 'priority': \"\n                                \"must be >= 1\"\n                            )\n\n        # Validate commands; track renames so hook references can be rewritten.\n        rename_map: Dict[str, str] = {}\n        for cmd in commands:\n            if not isinstance(cmd, dict):\n                raise ValidationError(\n                    \"Each command entry in 'provides.commands' must be a mapping\"\n                )\n            if \"name\" not in cmd or \"file\" not in cmd:\n                raise ValidationError(\"Command missing 'name' or 'file'\")\n            # The pattern match below would raise a bare TypeError on a\n            # non-string name (``name: 2``), escaping the ValidationError\n            # contract. The 'file' field needs no check here:\n            # relative_extension_path_violation() below already rejects a\n            # non-string value.","sourceCodeStart":418,"sourceCodeEnd":454,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/extensions/__init__.py#L418-L454","documentation":"Every element of provides.commands must be a mapping (dict) describing one command (with name and file keys). A non-dict element — string, number, list — is rejected before any key checks run.","triggerScenarios":"`provides:\\n  commands:\\n    - check` — a bare string element instead of a mapping. isinstance(cmd, dict) fails on the first loop iteration.","commonSituations":"Author writes a shorthand list of command names assuming the file is derived, or a malformed list-of-lists from a bad merge.","solutions":["Make each entry a mapping: `- name: check\\n  file: commands/check.md`.","Provide both name and file for every command.","Avoid shorthand — the schema has no string-only command form."],"exampleFix":"# before\nprovides:\n  commands:\n    - check\n\n# after\nprovides:\n  commands:\n    - name: check\n      file: commands/check.md","handlingStrategy":"type-guard","validationCode":"def commands_are_mappings(data: dict) -> bool:\n    cmds = (data.get(\"provides\") or {}).get(\"commands\") or []\n    return all(isinstance(c, dict) for c in cmds)","typeGuard":"def is_command_entry(v: object) -> bool:\n    return isinstance(v, dict) and \"name\" in v and \"file\" in v","tryCatchPattern":null,"preventionTips":["No string shorthand for commands — every entry needs name and file keys.","Write entries as `- name: x` / `file: y` pairs from a snippet template."],"tags":["extension-manifest","validation","commands"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}