{"record":{"id":"94b31adf46bcddd4","repo":"github/spec-kit","slug":"event-event-name-missing-required-command-st","errorCode":null,"errorMessage":"Event '{event_name}' missing required 'command' string","messagePattern":"Event '(.+?)' missing required 'command' string","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/events.py","lineNumber":1793,"sourceCode":"def validate_events(data: dict[str, Any]) -> None:\n    \"\"\"Validate ``events`` field in extension manifest data.\"\"\"\n    from .extensions import ValidationError\n\n    events = data.get(\"events\")\n    if \"events\" in data and not isinstance(events, dict):\n        raise ValidationError(\"Invalid events: expected a mapping\")\n    if events:\n        for event_name, event_config in events.items():\n            if not isinstance(event_config, dict):\n                raise ValidationError(\n                    f\"Invalid event '{event_name}': expected a mapping\"\n                )\n            command = event_config.get(\"command\")\n            # #17: command must be a non-empty string. A truthy non-string\n            # (e.g. command: [foo]) would pass a bare truthiness check and\n            # later render into invalid native configuration.\n            if not isinstance(command, str) or not command.strip():\n                raise ValidationError(\n                    f\"Event '{event_name}' missing required 'command' string\"\n                )\n            if event_name not in CANONICAL_EVENTS:\n                raise ValidationError(\n                    f\"Unknown event '{event_name}': \"\n                    f\"must be one of {sorted(CANONICAL_EVENTS)}\"\n                )\n            # C10: matcher must be a string (or absent). A non-string matcher\n            # such as `matcher: []` would later crash by_matcher.setdefault.\n            matcher = event_config.get(\"matcher\")\n            if matcher is not None and not isinstance(matcher, str):\n                raise ValidationError(\n                    f\"Event '{event_name}' has invalid 'matcher': must be a string\"\n                )\n            timeout = event_config.get(\"timeout\")\n            if timeout is not None:\n                if not isinstance(timeout, int) or isinstance(timeout, bool) or timeout <= 0:\n                    raise ValidationError(","sourceCodeStart":1775,"sourceCodeEnd":1811,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/events.py#L1775-L1811","documentation":"Thrown by validate_events() when an event entry's `command` is missing, empty, whitespace-only, or not a string (issue #17). The strict isinstance check exists because a truthy non-string like `command: [foo]` would pass a bare truthiness check and later render into invalid native agent configuration.","triggerScenarios":"Manifest event config contains `command:` (null), `command: \"\"`, `command: \"   \"`, or `command: [./run.sh]`; validate_events raises during manifest load/validation.","commonSituations":"Leaving command blank while drafting the manifest; YAML unquoted `command: [foo]` parsing as a list; using a placeholder like `command: TODO` that is fine, vs an empty stub that is not.","solutions":["Set `command` to a non-empty string, e.g. `command: \"./scripts/hook.sh\"`.","If the event is not ready, remove the whole event entry from the manifest rather than leaving a blank command.","Re-run the extension install/refresh."],"exampleFix":"# before\nevents:\n  pre_tool_use:\n    command:\n\n# after\nevents:\n  pre_tool_use:\n    command: \"./scripts/hook.sh\"","handlingStrategy":"validation","validationCode":"cmd = event_config.get(\"command\")\nif not isinstance(cmd, str) or not cmd.strip():\n    raise SystemExit(\"each event needs a non-empty string 'command'\")","typeGuard":"def has_valid_command(cfg: dict) -> bool:\n    cmd = cfg.get(\"command\")\n    return isinstance(cmd, str) and bool(cmd.strip())","tryCatchPattern":"except ValidationError as e:\n    if \"missing required 'command'\" in str(e):\n        remove_or_fill_event(event_name)","preventionTips":["Fill in command before installing; remove unfinished event entries instead of stubbing them.","Quote commands; avoid YAML list syntax for a single command."],"tags":["events","validation","command","manifest"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}