github/spec-kit · error · ValidationError

Invalid hooks: expected a mapping

Error message

Invalid hooks: expected a mapping

What it means

The optional top-level hooks section must be a mapping keyed by hook/event name, where each value is a single mapping or a list of mappings (normalized by coerce_hook_entries). A non-dict hooks value is rejected before per-hook validation.

Source

Thrown at src/specify_cli/extensions/__init__.py:390

        provides = self.data["provides"]
        if not isinstance(provides, dict):
            raise ValidationError(
                f"Invalid provides: expected a mapping, got {type(provides).__name__}"
            )
        commands = provides.get("commands", [])
        templates = provides.get("templates", [])
        scripts = provides.get("scripts", [])
        hooks = self.data.get("hooks")
        events = self.data.get("events")

        if "commands" in provides and not isinstance(commands, list):
            raise ValidationError("Invalid provides.commands: expected a list")
        if "templates" in provides and not isinstance(templates, list):
            raise ValidationError("Invalid provides.templates: expected a list")
        if "scripts" in provides and not isinstance(scripts, list):
            raise ValidationError("Invalid provides.scripts: expected a list")
        if "hooks" in self.data and not isinstance(hooks, dict):
            raise ValidationError("Invalid hooks: expected a mapping")
        if "events" in self.data:
            from ..events import validate_events
            validate_events(self.data)

        has_commands = bool(commands)
        has_hooks = bool(hooks)
        has_events = bool(events)
        has_templates = bool(templates)
        has_scripts = bool(scripts)

        if not has_commands and not has_hooks and not has_events and not has_templates and not has_scripts:
            raise ValidationError(
                "Extension must provide at least one command, hook, or event "
                "(or a declared template/script)"
            )

        self._validate_provided_artifacts(templates, section="templates", singular="template")
        self._validate_provided_artifacts(scripts, section="scripts", singular="script")

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Rewrite hooks as a mapping: `hooks:\n post-install:\n command: ./script.sh`.
  2. Remove list dashes at the hooks level; dashes belong only inside a hook's entry list.
  3. Use a mapping or list-of-mappings for each hook value as per-hook validation expects.

Example fix

# before
hooks:
  - post-install:
      command: ./setup.sh

# after
hooks:
  post-install:
    command: ./setup.sh
Defensive patterns

Strategy: validation

Validate before calling

def hooks_ok(data: dict) -> bool:
    return "hooks" not in data or isinstance(data["hooks"], dict)

Type guard

def is_hooks_mapping(data: dict) -> bool:
    return "hooks" not in data or isinstance(data["hooks"], dict)

Prevention

When it happens

Trigger: `hooks:` set to a list of `[event_name, config]` pairs, or a string. isinstance(hooks, dict) fails.

Common situations: Author writes hooks as a YAML list (one dash per hook) instead of a keyed mapping, which is the more common YAML shape for named entries.

Related errors


AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14). Data as JSON: /api/errors/355da9298205473a. Report an issue: GitHub.