github/spec-kit · error · EventRefreshError
failures
Error message
failures
What it means
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.
Source
Thrown at src/specify_cli/events.py:1770
# is both unsafe and redundant.
# S7: resolve this integration's persisted parsed_options so a
# stored --events false is honored across extension lifecycle
# changes; passing None would re-enable events the user disabled.
_, parsed_options = _resolve_integration_options(integration, state, key, None)
events_map = resolve_events(
key, integration.config, project_root, parsed_options
)
# install_integration_events handles both the populated case
# (writes new config, stripping stale owned entries) and the empty
# case (strips prior hooks for --events false / disabled override).
install_integration_events(integration, project_root, manifest, events_map)
manifest.save()
except Exception as exc:
logger.warning("Failed to refresh events for '%s': %s", key, exc)
failures.append((key, str(exc)))
if failures:
raise EventRefreshError(failures)
# -- Manifest validation ---------------------------------------------------
def validate_events(data: dict[str, Any]) -> None:
"""Validate ``events`` field in extension manifest data."""
from .extensions import ValidationError
events = data.get("events")
if "events" in data and not isinstance(events, dict):
raise ValidationError("Invalid events: expected a mapping")
if events:
for event_name, event_config in events.items():
if not isinstance(event_config, dict):
raise ValidationError(
f"Invalid event '{event_name}': expected a mapping"
)
command = event_config.get("command")View on GitHub (pinned to bf88c9f9a8)
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.
Defensive patterns
Strategy: try-catch
Try / catch
try:
refresh_installed_extension_events(project_root)
except EventRefreshError as e:
for key, msg in e.failures: # (integration_key, root_cause) pairs
logger.error("events refresh failed for %s: %s", key, msg)
# proceed / report — root causes are independent per extension Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- Unknown event '{event_name}': must be one of {sorted(CANONIC
- Event '{event_name}' handler missing required non-empty 'com
- Event '{event_name}' handler has invalid 'matcher': must be
- {exc}
- Directory not found: {source_path}
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/fa58cd8e06ac90ae.
Report an issue: GitHub.