github/spec-kit · error · ValidationError

Invalid hook '{hook_name}': expected a mapping or list of ma

Error message

Invalid hook '{hook_name}': expected a mapping or list of mappings

What it means

Each entry produced by coerce_hook_entries(hook_config) must be a mapping. coerce_hook_entries normalizes a single mapping or a list into entries; after normalization anything that is not a dict (e.g. a bare string entry inside the list) is rejected.

Source

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

            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")

        # Validate hook values (if present).
        # Each event is a single mapping or a list of mappings.
        if hooks:
            for hook_name, hook_config in hooks.items():
                if isinstance(hook_config, list) and not hook_config:
                    raise ValidationError(
                        f"Invalid hook '{hook_name}': list must contain at least one entry"
                    )
                for entry in coerce_hook_entries(hook_config):
                    if not isinstance(entry, dict):
                        raise ValidationError(
                            f"Invalid hook '{hook_name}': "
                            "expected a mapping or list of mappings"
                        )
                    if not entry.get("command"):
                        raise ValidationError(
                            f"Hook '{hook_name}' missing required 'command' field"
                        )
                    if "priority" in entry:
                        priority = entry["priority"]
                        if not isinstance(priority, int) or isinstance(priority, bool):
                            raise ValidationError(
                                f"Hook '{hook_name}' has invalid 'priority': "
                                "must be an integer"
                            )
                        if priority < 1:
                            raise ValidationError(
                                f"Hook '{hook_name}' has invalid 'priority': "
                                "must be >= 1"

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Make every entry a mapping: `- command: ./setup.sh`.
  2. Add other supported keys (e.g. priority) inside the mapping, not as siblings.
  3. A single mapping (no list) is also fine — the normalizer wraps it.

Example fix

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

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

Strategy: type-guard

Validate before calling

def hook_entries_all_mappings(data: dict) -> bool:
    hooks = data.get("hooks") or {}
    for cfg in hooks.values():
        entries = cfg if isinstance(cfg, list) else [cfg]
        if not all(isinstance(e, dict) for e in entries):
            return False
    return True

Type guard

def is_hook_entry(v: object) -> bool:
    return isinstance(v, dict)

Prevention

When it happens

Trigger: `hooks:\n post-install:\n - ./setup.sh` — the list element is a string, not a mapping with a command key. The isinstance(entry, dict) check fails.

Common situations: Author writes hook entries as bare command strings, assuming the schema accepts a string shorthand, or mixes a string into an otherwise valid list of mappings.

Related errors


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