-
Notifications
You must be signed in to change notification settings - Fork 2.3k
fix: guard against undefined output.output in tool.execute.after hooks #1735
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Conversation
MCP tools may not return output.output as a string, causing TypeError when calling .toLowerCase(). This fix adds a guard to check if output.output exists and is a string before attempting to call string methods on it. Fixes crash: TypeError: undefined is not an object (evaluating 'output.output.toLowerCase')
|
Thank you for your contribution! Before we can merge this PR, we need you to sign our Contributor License Agreement (CLA). To sign the CLA, please comment on this PR with: This is a one-time requirement. Once signed, all your future contributions will be automatically accepted. I have read the CLA Document and I hereby sign the CLA well0nez seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. |
|
I have read the CLA Document and I hereby sign the CLA |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No issues found across 2 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Auto-approved: The changes add guards against undefined output values, reducing potential errors; no regressions detected and criteria are fully met.
|
Please merge soon :) |
Full Audit:
|
| # | Hook | File | Line | Pattern | PR #1735 |
|---|---|---|---|---|---|
| 1 | comment-checker | hook.ts |
L95 | output.output.toLowerCase() |
Fixed |
| 2 | edit-error-recovery | hook.ts |
L47 | output.output.toLowerCase() |
Fixed |
| 3 | task-resume-info | hook.ts |
L24-27 | .startsWith(), .includes(), .trimEnd() |
Missing |
| 4 | delegate-task-retry | hook.ts |
L14 | Passed to detectDelegateTaskError() which calls .includes() at patterns.ts:65 |
Missing |
The same one-liner used in this PR resolves all four:
if (!output.output || typeof output.output !== "string") returnSilent Corruption (undefined += "string" = "undefinedstring")
These hooks append to output.output without checking its type. When output.output is undefined, JavaScript coerces it to the string "undefined" and concatenates, producing corrupted output like "undefinedRemember to use...":
| Hook | File | Line |
|---|---|---|
| agent-usage-reminder | hook.ts |
L80 |
| task-reminder | hook.ts |
L42 |
| category-skill-reminder | hook.ts |
L109 |
| context-window-monitor | hook.ts |
L77 |
| rules-injector | injector.ts |
L119 |
| directory-agents-injector | injector.ts |
L49 |
| directory-readme-injector | injector.ts |
L49 |
These won't crash, but they produce garbage output for MCP tools. A guard like if (typeof output.output !== "string") return or changing output.output += to output.output = (output.output ?? "") + would fix them.
Already-Safe Hooks (for reference)
tool-output-truncator, empty-task-response-detector, atlas/tool-execute-after, interactive-bash-session, and claude-code-hooks/tool-execute-after-handler all have proper guards (typeof checks, optional chaining, or falsy guards).
Root Cause
Since ai@6.0.0 (Dec 22, 2025), ToolResultPart.output is no longer the raw tool result. It is now wrapped by createToolModelOutput() (introduced in vercel/ai#6784) into a ToolResultOutput envelope:
Before: output.output → "some string" (raw tool result)
After: output.output → { type: "text", value: "some string" }
The hooks expect the old shape. For MCP tools specifically, output.output resolves to undefined because the envelope object has no .output property — only .type and .value. Built-in tools are unaffected because OpenCode's prompt.ts wraps their results into { output: string, title: string, metadata: object } before the SDK transforms them.
Related
- MCP tools crash: TypeError on value.output.output in processor.ts (AI SDK 6.0.74 breaking change) anomalyco/opencode#13042 (upstream root cause, closed as oh-my-opencode bug)
- Kubernetes MCP server tools fail with TypeError: output.output.toLowerCase anomalyco/opencode#12987 (duplicate)
- [Bug]: Unguarded output.output access in tool.execute.after hooks crashes all MCP tools #1746, TypeError: output.output.toLowerCase() crashes on MCP tools with undefined output #1737, FYI: v3.4.1 broke all external MCP tools (published & yanked) #1720
Summary
MCP tools may not return
output.outputas a string, causing aTypeErrorwhen calling.toLowerCase()on it.Error:
TypeError: undefined is not an object (evaluating 'output.output.toLowerCase')This happens when using MCP servers like
ida-pro-mcpwhere the tool output format differs from standard OpenCode tools.Changes
edit-error-recovery/hook.tsto check ifoutput.outputexists and is a string before calling string methodscomment-checker/hook.tswith the same protectionFiles Changed
src/hooks/edit-error-recovery/hook.tssrc/hooks/comment-checker/hook.tsTesting
Tested with
ida-pro-mcpMCP server - the error no longer occurs and MCP tools work correctly.Summary by cubic
Prevent crashes in tool.execute.after hooks by guarding against undefined or non-string output.output before calling .toLowerCase(). Fixes TypeErrors with MCP servers like ida-pro-mcp and keeps tool execution stable.
Written for commit b282697. Summary will update on new commits.