github/spec-kit · warning · ValidationError
Unknown event '{event_name}': must be one of {sorted(CANONIC
Error message
Unknown event '{event_name}': must be one of {sorted(CANONICAL_EVENTS)} What it means
Event handler configuration only accepts the canonical snake_case event names: session_start, pre_tool_use, post_tool_use, session_end, user_prompt_submit, and stop. An unknown key raises ValidationError from `_validate_resolved_event`; in the normal resolve_events flow the exception is caught and the entire user YAML override is abandoned with a warning, keeping built-in/extension events.
Source
Thrown at src/specify_cli/events.py:802
if not isinstance(entry, dict):
logger.warning("Skipping malformed event handler (expected a mapping): %r", entry)
continue
handlers.append(entry)
return handlers
def _validate_resolved_event(event_name: str, handlers: list[dict[str, Any]]) -> None:
"""Validate a resolved event's handlers, raising a user-facing error.
Raised for structural problems the user must fix (unknown event name,
handler missing a ``command``, or ``command`` not a non-empty string per
#17). Malformed-but-skipable entries are already dropped by
``_normalize_handlers``.
"""
from .extensions import ValidationError
if event_name not in CANONICAL_EVENTS:
raise ValidationError(
f"Unknown event '{event_name}': must be one of {sorted(CANONICAL_EVENTS)}"
)
for handler in handlers:
command = handler.get("command")
if not isinstance(command, str) or not command.strip():
raise ValidationError(
f"Event '{event_name}' handler missing required non-empty 'command' string"
)
# C10: matcher must be a string (or absent). A non-string matcher such
# as `matcher: []` passes extension validation but later crashes
# by_matcher.setdefault(matcher, ...) with TypeError: unhashable type.
matcher = handler.get("matcher")
if matcher is not None and not isinstance(matcher, str):
raise ValidationError(
f"Event '{event_name}' handler has invalid 'matcher': "
"must be a string"
)
timeout = handler.get("timeout")View on GitHub (pinned to bf88c9f9a8)
Solutions
- Replace the invalid key with one of: session_start, pre_tool_use, post_tool_use, session_end, user_prompt_submit, stop.
- Use snake_case exactly; names are case-sensitive.
- Re-run integration install/upgrade or event resolution and confirm the warning no longer appears.
- If an extension itself declares the bad name, fix its extension.yml events mapping.
Example fix
# .specify/integration-events.yml (before)
integrations:
claude:
events:
SessionStart:
command: speckit.session-start
# after
integrations:
claude:
events:
session_start:
command: speckit.session-start Defensive patterns
Strategy: validation
Validate before calling
from specify_cli.events import CANONICAL_EVENTS
def override_events_are_canonical(override: dict) -> bool:
integrations = override.get("integrations", {})
return all(
event in CANONICAL_EVENTS
for entry in integrations.values()
if isinstance(entry, dict)
for event in entry.get("events", {})
) Type guard
from typing import Any, TypeGuard
from specify_cli.events import CANONICAL_EVENTS
def is_canonical_event_name(value: Any) -> TypeGuard[str]:
return isinstance(value, str) and value in CANONICAL_EVENTS Try / catch
from specify_cli.extensions import ValidationError
try:
_validate_resolved_event(event_name, handlers)
except ValidationError as exc:
if str(exc).startswith("Unknown event"):
warn_and_ignore_entire_override(event_name)
else:
raise Prevention
- Copy event names from CANONICAL_EVENTS, not agent-native hook names.
- Use snake_case and remember names are case-sensitive.
- Watch for the 'ignoring entire override' warning after changing integration-events.yml.
When it happens
Trigger: Writing `.specify/integration-events.yml` with a CamelCase native hook name such as SessionStart, a hyphenated name such as pre-tool-use, or an unsupported event name under an integration's `events` mapping.
Common situations: Copying names from Claude Code's native hooks JSON or an agent vendor's documentation instead of Spec Kit's canonical event vocabulary.
Related errors
- Event '{event_name}' handler missing required non-empty 'com
- Event '{event_name}' handler has invalid 'matcher': must be
- Event '{event_name}' handler has invalid 'timeout': must be
- Invalid events: expected a mapping
- Invalid event '{event_name}': expected a mapping
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/38277e3ed68cc511.
Report an issue: GitHub.