ruvnet/ruflo · error · Error
Hook for event ${this.event} requires a handler
Error message
Hook for event ${this.event} requires a handler What it means
HookBuilder.build() validates that a handler was set via .handle(fn) and throws otherwise. It is builder validation: the resulting HookDefinition would be unexecutable, so build() refuses to emit it. Conditions and transformers are optional; only the handler is mandatory.
Source
Thrown at v3/@claude-flow/plugins/src/hooks/index.ts:353
transform(transformer: (data: unknown) => unknown): this {
this.transformers.push(transformer);
return this;
}
/**
* Set the handler function.
*/
handle(handler: HookHandler): this {
this.handler = handler;
return this;
}
/**
* Build the hook definition.
*/
build(): HookDefinition {
if (!this.handler) {
throw new Error(`Hook for event ${this.event} requires a handler`);
}
const originalHandler = this.handler;
const conditions = this.conditions;
const transformers = this.transformers;
// Wrap handler with conditions and transformers
const wrappedHandler: HookHandler = async (context: HookContext) => {
// Check conditions
for (const condition of conditions) {
if (!condition(context)) {
return { success: true, data: context.data };
}
}
// Apply transformers
let data = context.data;
for (const transformer of transformers) {View on GitHub (pinned to fa13ee4ad6)
Solutions
- Add .handle(fn) to the chain before .build()
- When the handler is genuinely optional-by-branch, provide a no-op default handler or only call build() once a handler is assigned
- Centralize builder completion in a single factory function that always sets a handler as its last step
Example fix
// before
const hook = builder.on('task:after').when(ctx => ctx.ok).build(); // throws
// after
const hook = builder
.on('task:after')
.when(ctx => ctx.ok)
.handle(async ctx => ({ success: true, data: ctx.data }))
.build(); Defensive patterns
Strategy: validation
Validate before calling
// Complete the builder in one factory so the handler can never be missing:
function buildHook(
builder: HookBuilder,
handler: HookHandler | undefined
): HookDefinition {
if (!handler) {
throw new Error('refusing to build hook without a handler');
}
return builder.handle(handler).build();
} Prevention
- Always end the fluent chain with .handle(fn) before .build()
- Provide a no-op default handler when wiring is conditional
- Let one factory own builder completion instead of scattering chains
When it happens
Trigger: Building a fluent chain that is missing .handle(): builder.on('x').when(cond).build(); conditional wiring where the branch that calls .handle() is skipped by a typo'd if or a falsy check; refactors that renamed the handle() call or moved it after build().
Common situations: Copy-pasted builder code with the handle line dropped; dynamically assembled builders whose handler depends on a runtime branch; incomplete first-draft code passing tests of construction but failing at build().
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- localCompute: no adapter for graphId=${input.graphId}
- Invalid completion type
- Router multimodal is enabled but LLM_ROUTER_MULTIMODAL_MODEL
- Routes config must be a flat array of routes
- Invalid route entry: ${JSON.stringify(r)}
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/ec95fd7e37c57a48.
Report an issue: GitHub.