{"record":{"id":"fa58cd8e06ac90ae","repo":"github/spec-kit","slug":"failures","errorCode":null,"errorMessage":"failures","messagePattern":"failures","errorType":"exception","errorClass":"EventRefreshError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/events.py","lineNumber":1770,"sourceCode":"            # is both unsafe and redundant.\n            # S7: resolve this integration's persisted parsed_options so a\n            # stored --events false is honored across extension lifecycle\n            # changes; passing None would re-enable events the user disabled.\n            _, parsed_options = _resolve_integration_options(integration, state, key, None)\n            events_map = resolve_events(\n                key, integration.config, project_root, parsed_options\n            )\n            # install_integration_events handles both the populated case\n            # (writes new config, stripping stale owned entries) and the empty\n            # case (strips prior hooks for --events false / disabled override).\n            install_integration_events(integration, project_root, manifest, events_map)\n            manifest.save()\n        except Exception as exc:\n            logger.warning(\"Failed to refresh events for '%s': %s\", key, exc)\n            failures.append((key, str(exc)))\n\n    if failures:\n        raise EventRefreshError(failures)\n\n\n# -- Manifest validation ---------------------------------------------------\n\ndef 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\")","sourceCodeStart":1752,"sourceCodeEnd":1788,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/events.py#L1752-L1788","documentation":"EventRefreshError is raised after a batch refresh of event configs across installed extensions/integrations: each per-extension failure was caught, logged as a warning ('Failed to refresh events for ...'), and accumulated into a `failures` list of (key, message) tuples; if any failed, the whole refresh aborts with this error. It is an aggregation wrapper, not a single root cause — inspect the pairs inside.","triggerScenarios":"Calling refresh_installed_extension_events (event refresh pass after install/update/uninstall): for one or more integration keys, resolve_events or install_integration_events raised any Exception; each is appended to failures and re-raised as EventRefreshError(failures).","commonSituations":"One extension's manifest has invalid events config (bad command, unknown event name, non-string matcher); a destination file is unwritable or symlinked (see the symlink guard); partial uninstall left a stale manifest pointing at missing files.","solutions":["Read the (key, message) pairs in the exception payload and the preceding log warnings to identify which integration failed and why.","Fix the root cause for that key (e.g. correct the extension's events mapping, repair permissions, remove a rogue symlink).","Re-run the refresh; extensions are processed independently so fixing the one bad entry clears the error.","If a stale/broken extension is the cause, uninstall it (`specify extension uninstall <key>`) and refresh again."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    refresh_installed_extension_events(project_root)\nexcept EventRefreshError as e:\n    for key, msg in e.failures:  # (integration_key, root_cause) pairs\n        logger.error(\"events refresh failed for %s: %s\", key, msg)\n    # proceed / report — root causes are independent per extension","preventionTips":["Treat this as an aggregate: always iterate failures instead of parsing the message string.","Validate each extension manifest before install so refresh-time failures never occur."],"tags":["events","aggregation","extensions","refresh"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}