Hook Kind Mismatch
Error:
Hook "X" is registered as both a logic hook and a UI/action zone contribution.
The Problem
Two different modules (or two entries in the same manifest) register the same hook name, but the entries classify into two different kinds:
- A logic hook — a
.js/.tsentry whose name doesn’t start withlauncher:and doesn’t end with:action. Compiled intovirtual:stnd/hooks, called viarunHook()/runPipeline(). - A UI/action zone contribution — everything else (
.astro/.sveltecomponents, or anylauncher:-prefixed /:action-suffixed entry regardless of file type). Compiled intovirtual:stnd/components, rendered via<Hook zone="...">or read directly asextensions[zone].
The Why
These are two disconnected virtual modules with different consumers. A hook name silently meaning two different things depending on which module registered it first means half the registrations are invisible to whichever consumer asked for the other kind — a runPipeline("X", ...) call would never see the UI-classified entries, and a <Hook zone="X"> would never see the logic-classified ones. No error, no warning — just a feature that silently doesn’t work for some of its contributors.
This mirrors launcher-trigger-collision and module-duplicate-id: the framework prefers a loud build-time failure over unpredictable, silently-partial behavior.
The Solution
- Rename one of the hooks. If the two features are genuinely distinct, give them different names.
- Match entry types. If they’re meant to be the same hook, make sure every registration classifies the same way — e.g. don’t mix a
.astroUI entry and a.tsaction entry under one name unless the name islauncher:-prefixed or:action-suffixed (which always forces UI/action classification). - Avoid
launcher:/:actionnaming for logic hooks. If you wantrunHook/runPipelinesemantics, don’t name the hooklauncher:*or*:action— those patterns always route to the UI/action pool regardless of entry type. See also hook-server-flag-ignored, the related trap this naming pattern creates.
Related Concepts
- modules: How the Standard module system works, including the full
hooks:contract. - launcher-trigger-collision: The same “fail loud on ambiguity” principle applied to launcher triggers.