{"record":{"id":"141a3b8c53a0e4ab","repo":"can1357/oh-my-pi","slug":"hook-failed-blocking-execution-string-err","errorCode":null,"errorMessage":"Hook failed, blocking execution: ${String(err)}","messagePattern":"Hook failed, blocking execution: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/extensibility/hooks/tool-wrapper.ts","lineNumber":68,"sourceCode":"\t\t\t\t\ttoolCallId,\n\t\t\t\t\tinput: normalizeToolEventInput(\n\t\t\t\t\t\tthis.tool.name,\n\t\t\t\t\t\tresolveToolEventInput(this.tool, params as Record<string, unknown>),\n\t\t\t\t\t),\n\t\t\t\t})) as ToolCallEventResult | undefined;\n\n\t\t\t\tif (callResult?.block) {\n\t\t\t\t\tconst reason = callResult.reason || \"Tool execution was blocked by a hook\";\n\t\t\t\t\tthrow new Error(reason);\n\t\t\t\t}\n\t\t\t\t// A non-blocking handler may replace the execution input. The returned object is the raw\n\t\t\t\t// input the tool runs with (handler-owned); it is not re-normalized. Skipped for `computer`\n\t\t\t\t// tool calls, whose real parameters are not represented by the event input.\n\t\t\t\tif (callResult?.input !== undefined && context?.toolCall?.providerMetadata?.type !== \"computer\") {\n\t\t\t\t\teffectiveParams = callResult.input as Static<TParameters>;\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// Hook error or block - throw to mark as error\n\t\t\t\tif (err instanceof Error) {\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\t\t\t\tthrow new Error(`Hook failed, blocking execution: ${String(err)}`);\n\t\t\t}\n\t\t}\n\n\t\t// Execute the actual tool, forwarding onUpdate for progress streaming\n\t\ttry {\n\t\t\tconst result = await this.tool.execute(toolCallId, effectiveParams, signal, onUpdate, context);\n\n\t\t\t// Emit tool_result event - hooks can modify the result\n\t\t\tif (this.hookRunner.hasHandlers(\"tool_result\")) {\n\t\t\t\tconst resultResult = (await this.hookRunner.emit({\n\t\t\t\t\ttype: \"tool_result\",\n\t\t\t\t\ttoolName: this.tool.name,\n\t\t\t\t\ttoolCallId,\n\t\t\t\t\tinput: normalizeToolEventInput(","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/extensibility/hooks/tool-wrapper.ts#L50-L86","documentation":"A hook handler itself threw a non-Error value while the tool was executing. Because hooks are fail-closed, any handler error blocks the tool call; non-Error throws are re-wrapped with this prefix (Error throws pass through unchanged).","triggerScenarios":"A registered tool-call hook throws a raw string/object or rejects with a non-Error while wrapper.execute() runs the pre-call hook chain.","commonSituations":"Hook authors using throw 'msg' instead of new Error('msg'); hooks with bugs (null deref producing weird throw shapes, e.g. throw undefined); async hook rejecting with a plain value.","solutions":["Fix the hook to throw Error instances and handle its own exceptions","Identify the offending hook from the stringified value after the prefix","Disable the hook/extension and retry the tool call","Wrap hook handler bodies in try/catch that convert failures to Error"],"exampleFix":"// before (in hook)\nthrow 'rule violation';\n// after\nthrow new Error('rule violation');","handlingStrategy":"try-catch","validationCode":"function hookIsSafe(fn) { try { fn({ name: 'probe' }); return true; } catch (e) { return e instanceof Error; } }","typeGuard":"function isError(e: unknown): e is Error { return e instanceof Error; }","tryCatchPattern":"try { await tool.execute(params); } catch (err) {\n  if (err instanceof Error && err.message.startsWith('Hook failed, blocking execution:')) {\n    logger.warn('hook crashed; disabled until fixed', { detail: err.message });\n  } else throw err;\n}","preventionTips":["Wrap hook handler bodies in try/catch that convert failures to Error","Never throw raw strings/objects from hooks","Unit-test hooks against malformed inputs","Fail hooks with block+reason instead of throwing when rejecting a call"],"tags":["hook","extension","fail-closed","tool-execution"],"backgroundTag":"extension-hook-threw-non-error","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}