Tool use recursion error
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
With increasing frequency, tool use results in a Claude crash back to CLI. Seems to be a recursion error.
Unfortunately, this tends to happen during complex work, and is frustrating because it costs both time and money. While each individual instance isn't too costly in and of itself, the aggregate of these repeated crashes costs enough to warrant demanding credits back or abandoning this tool until things get fixed.
What Should Happen?
The tool use shouldn't crash to CLI.
Error Messages/Logs
file:///Users/randolph/.nvm/versions/node/v22.14.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:3437
`,isMeta:!0}),...A]}async function t59(A,Q){if(GrQ())return;let[{tools:B},G,Z,Y]=await Promise.all([pI1(A),rz(Q),hV(),OD()]),J=Y.gitStatus?.length??0,X=Z.claudeMd?.length??0,I=J+X,W=y9();setTimeout(()=>W.abort(),1000);let K=l1(),V=GFA(Q),H=BFA(V,K),D=await emA(K,W.signal,H),F=0,E=0,z=0,$=0,L=0,O=G.filter((_)=>!_.isMcp);F=B.length,$=O.length;let M=new Set;for(let _ of B){let j=_.name.split("__");if(j.length>=3&&j[1])M.add(j[1])}E=M.size;try{if(B.length>0){let _=I3(),{mcpToolTokens:j}=await TkA(G,async()=>Q,null,_);z=j}if(O.length>0)L=await Hg2(G,async()=>Q,null)}catch{}l("tengu_context_size",{git_status_size:J,claude_md_size:X,total_context_size:I,project_file_count_rounded:D,mcp_tools_count:F,mcp_servers_count:E,mcp_tools_tokens:z,non_mcp_tools_count:$,non_mcp_tools_tokens:L})}function e59(A,Q,B){switch(A.name){case pd:{let G=$W(B);if(G)return{...Q,plan:G};return Q}case W9.name:{let G=W9.inputSchema.parse(Q),{command:Z,timeout:Y,description:J,run_in_background:X}=G,I=Z.replace(`cd ${l1()} && `,"");if(I=I.replace(/\\\\;/g,"\\;"),/^echo\s+["']?[^|&;><]*["']?$/i.test(I.trim()))l("tengu_bash_tool_simple_echo",{});return{command:I,description:J,...Y?{timeout:Y}:{},...J?{description:J}:{},...X?{run_in_background:X}:{},..."dangerouslyDisableSandbox"in G&&G.dangerouslyDisableSandbox?{dangerouslyDisableSandbox:G.dangerouslyDisableSandbox}:{}}}case gz.name:{let G=gz.inputSchema.parse(Q),{file_path:Z,edits:Y}=TN2({file_path:G.file_path,edits:[{old_string:G.old_string,new_string:G.new_string,replace_all:G.replace_all}]});return{replace_all:Y[0].replace_all,file_path:Z,old_string:Y[0].old_string,new_string:Y[0].new_string}}case hz.name:{let G=hz.inputSchema.parse(Q);return{file_path:G.file_path,content:RH0(G.content)}}case uDA:{let G=Q,Z=G.task_id??G.agentId??G.bash_id,Y=G.timeout??(typeof G.wait_up_to==="number"?G.wait_up_to*1000:void 0);return{task_id:Z??"",block:G.block??!0,timeout:Y??30000}}default:return Q}}function A79(A,Q){switch(A.name){case pd:{if(Q&&typeof Q==="object"&&"plan"in Q){let{plan:B,...G}=Q;return G}return Q}default:return Q}}var iG7;var id=w(()=>{vW1();U8();zY();K01();V0();oQ();Zy();G2();$Y();pK();Ns();yr();dd();OZ();sH();B0();y1();JK1();g2();cw();S8A();rq();fS();eF();iG7=c(sh2(),1)});var Q79=w(()=>{V0();oQ();IZ();id();OZ();g2();B0()});var B79=w(()=>{zY();pK();dd();Ns();i4A();b1();Q79()});function SF1(A){G79.push(A)}async function Z79(A,Q,B,G,Z,Y){let J={messages:A,systemPrompt:Q,userContext:B,systemContext:G,toolUseContext:Z,querySource:Y};for(let X of G79)try{await X(J)}catch(I){r(I instanceof Error?I:Error(`Post-sampling hook failed: ${I}`))}}var G79;var tfA=w(()=>{b1();G79=[]});class xF1{toolDefinitions;canUseTool;tools=[];toolUseContext;hasErrored=!1;discarded=!1;progressAvailableResolve;constructor(A,Q,B){this.toolDefinitions=A;this.canUseTool=Q;this.toolUseContext=B}discard(){this.discarded=!0}addTool(A,Q){let B=this.toolDefinitions.find((Y)=>Y.name===A.name);if(!B){this.tools.push({id:A.id,block:A,assistantMessage:Q,status:"completed",isConcurrencySafe:!0,pendingProgress:[],results:[N0({content:[{type:"tool_result",content:`<tool_use_error>Error: No such tool available: ${A.name}</tool_use_error>`,is_error:!0,tool_use_id:A.id}],toolUseResult:`Error: No such tool available: ${A.name}`,sourceToolAssistantUUID:Q.uuid})]});return}let G=B.inputSchema.safeParse(A.input),Z=G?.success?B.isConcurrencySafe(G.data):!1;this.tools.push({id:A.id,block:A,assistantMessage:Q,status:"queued",isConcurrencySafe:Z,pendingProgress:[]}),this.processQueue()}canExecuteTool(A){let Q=this.tools.filter((B)=>B.status==="executing");return Q.length===0||A&&Q.every((B)=>B.isConcurrencySafe)}async processQueue(){for(let A of this.tools){if(A.status!=="queued")continue;if(this.canExecuteTool(A.isConcurrencySafe))await this.executeTool(A);else if(!A.isConcurrencySafe)break}}createSyntheticErrorMessage(A,Q){if(Q==="user_interrupted")return N0({content:[{type:"tool_result",content:W6A,is_error:!0,tool_use_id:A}],toolUseResult:"User rejected tool use"});if(Q==="streaming_fallback")return N0({content:[{type:"tool_result",content:"<tool_use_error>Error: Streaming fallback - tool execution discarded</tool_use_error>",is_error:!0,tool_use_id:A}],toolUseResult:"Streaming fallback - tool execution discarded"});return N0({content:[{type:"tool_result",content:"<tool_use_error>Sibling tool call errored</tool_use_error>",is_error:!0,tool_use_id:A}],toolUseResult:"Sibling tool call errored"})}getAbortReason(){if(this.discarded)return"streaming_fallback";if(this.hasErrored)return"sibling_error";if(this.toolUseContext.abortController.signal.aborted)return"user_interrupted";return null}async executeTool(A){A.status="executing",this.toolUseContext.setInProgressToolUseIDs((Y)=>new Set([...Y,A.id]));let Q=[],B=[],Z=(async()=>{let Y=this.getAbortReason();if(Y){Q.push(this.createSyntheticErrorMessage(A.id,Y)),A.results=Q,A.contextModifiers=B,A.status="completed";return}let J=yF1(A.block,A.assistantMessage,this.canUseTool,this.toolUseContext),X=!1;for await(let I of J){let W=this.getAbortReason();if(W&&!X){Q.push(this.createSyntheticErrorMessage(A.id,W));break}if(I.message.type==="user"&&Array.isArray(I.message.message.content)&&I.message.message.content.some((V)=>V.type==="tool_result"&&V.is_error===!0))this.hasErrored=!0,X=!0;if(I.message)if(I.message.type==="progress"){if(A.pendingProgress.push(I.message),this.progressAvailableResolve)this.progressAvailableResolve(),this.progressAvailableResolve=void 0}else Q.push(I.message);if(I.contextModifier)B.push(I.contextModifier.modifyContext)}if(A.results=Q,A.contextModifiers=B,A.status="completed",!A.isConcurrencySafe&&B.length>0)for(let I of B)this.toolUseContext=I(this.toolUseContext)})();A.promise=Z,Z.finally(()=>{this.processQueue()})}*getCompletedResults(){if(this.discarded)return;for(let A of this.tools){while(A.pendingProgress.length>0)yield{message:A.pendingProgress.shift()};if(A.status==="yielded")continue;if(A.status==="completed"&&A.results){A.status="yielded";for(let Q of A.results)yield{message:Q};nG7(this.toolUseContext,A.id)}else if(A.status==="executing"&&!A.isConcurrencySafe)break}}hasPendingProgress(){return this.tools.some((A)=>A.pendingProgress.length>0)}async*getRemainingResults(){if(this.discarded)return;while(this.hasUnfinishedTools()){await this.processQueue();for(let A of this.getCompletedResults())yield A;if(this.hasExecutingTools()&&!this.hasCompletedResults()&&!this.hasPendingProgress()){let A=this.tools.filter((B)=>B.status==="executing"&&B.promise).map((B)=>B.promise),Q=new Promise((B)=>{this.progressAvailableResolve=B});if(A.length>0)await Promise.race([...A,Q])}}for(let A of this.getCompletedResults())yield A}hasCompletedResults(){return this.tools.some((A)=>A.status==="completed")}hasExecutingTools(){return this.tools.some((A)=>A.status==="executing")}hasUnfinishedTools(){return this.tools.some((A)=>A.status!=="yielded")}getUpdatedContext(){return this.toolUseContext}}function nG7(A,Q){A.setInProgressToolUseIDs((B)=>new Set([...B].filter((G)=>G!==Q)))}var Y79=w(()=>{Et();oQ()});import{randomUUID as aG7}from"crypto";function vF1(A){return async(Q)=>{try{if(!await A.shouldRun(Q))return;let G=aG7(),Z=A.buildMessages(Q);Q.queryMessageCount=Z.length;let Y=A.systemPrompt?[A.systemPrompt]:Q.systemPrompt,X=A.useTools??!0?Q.toolUseContext.options.tools:[],I=A.getModel(),W=await Np({messages:Z,systemPrompt:Y,maxThinkingTokens:0,tools:X,signal:y9().signal,options:{getToolPermissionContext:async()=>{return(await Q.toolUseContext.getAppState()).toolPermissionContext},model:I,toolChoice:void 0,isNonInteractiveSession:Q.toolUseContext.options.isNonInteractiveSession,hasAppendSystemPrompt:!!Q.toolUseContext.options.appendSystemPrompt,temperatureOverride:0,agents:Q.toolUseContext.options.agentDefinitions.activeAgents,querySource:A.name,mcpTools:[],agentId:Q.toolUseContext.agentId}}),K=W.message.content.filter((V)=>V.type==="text").map((V)=>V.text).join("").trim();try{let V=A.parseResponse(K,Q);A.logResult({type:"success",queryName:A.name,result:V,messageId:W.message.id,model:I,uuid:G},Q)}catch(V){A.logResult({type:"error",queryName:A.name,error:V,uuid:G},Q)}}catch(B){r(B instanceof Error?B:Error(`API query hook ${A.name} failed`))}}}var tO0=w(()=>{IZ();OZ();b1()});async function J79(){return}async function X79(A){if(eO0)await eO0(A)}var eO0=null;var AM0=w(()=>{tO0();oQ();V0();U8();g2();id()});var efA;var QM0=w(()=>{efA=class efA{returned;queue=[];readResolve;readReject;isDone=!1;hasError;started=!1;constructor(A){this.returned=A}[Symbol.asyncIterator](){if(this.started)throw Error("Stream can only be iterated once");return this.started=!0,this}next(){if(this.queue.length>0)return Promise.resolve({done:!1,value:this.queue.shift()});if(this.isDone)return Promise.resolve({done:!0,value:void 0});if(this.hasError)return Promise.reject(this.hasError);return new Promise((A,Q)=>{this.readResolve=A,this.readReject=Q})}enqueue(A){if(this.readResolve){let Q=this.readResolve;this.readResolve=void 0,this.readReject=void 0,Q({done:!1,value:A})}else this.queue.push(A)}done(){if(this.isDone=!0,this.readResolve){let A=this.readResolve;this.readResolve=void 0,this.readReject=void 0,A({done:!0,value:void 0})}}error(A){if(this.hasError=A,this.readReject){let Q=this.readReject;this.readResolve=void 0,this.readReject=void 0,Q(A)}}return(){if(this.isDone=!0,this.returned)this.returned();return Promise.resolve({done:!0,value:void 0})}}});import{randomUUID as I79}from"crypto";function oG7(){return parseInt(process.env.CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY||"",10)||10}function*BM0(A,Q){for(let B of A){let G=B.message.content.filter((Z)=>Z.type==="tool_use");for(let Z of G)yield N0({content:[{type:"tool_result",content:Q,is_error:!0,tool_use_id:Z.id}],toolUseResult:Q,sourceToolAssistantUUID:B.uuid})}}async function*yN({messages:A,systemPrompt:Q,userContext:B,systemContext:G,canUseTool:Z,toolUseContext:Y,autoCompactTracking:J,fallbackModel:X,stopHookActive:I,querySource:W,maxOutputTokensOverride:K,maxOutputTokensRecoveryCount:V=0}){if(yield{type:"stream_request_start"},h6("query_fn_entry"),!Y.agentId)p6A("query_started");let H=Y.queryTracking?{chainId:Y.queryTracking.chainId,depth:Y.queryTracking.depth+1}:{chainId:I79(),depth:0},D=H.chainId;Y={...Y,queryTracking:H};let F=TS(A),E=J;h6("query_microcompact_start");let z=await bd(F,void 0,Y);if(F=z.messages,z.compactionInfo?.systemMessage)yield z.compactionInfo.systemMessage;h6("query_microcompact_end"),h6("query_autocompact_start");let{compactionResult:$}=await Wy2(F,Y,W);if(h6("query_autocompact_end"),$){let{preCompactTokenCount:s,postCompactTokenCount:FA,compactionUsage:KA}=$;if(l("tengu_auto_compact_succeeded",{originalMessageCount:A.length,compactedMessageCount:$.summaryMessages.length+$.attachments.length+$.hookResults.length,preCompactTokenCount:s,postCompactTokenCount:FA,compactionInputTokens:KA?.input_tokens,compactionOutputTokens:KA?.output_tokens,compactionCacheReadTokens:KA?.cache_read_input_tokens??0,compactionCacheCreationTokens:KA?.cache_creation_input_tokens??0,compactionTotalTokens:KA?KA.input_tokens+(KA.cache_creation_input_tokens??0)+(KA.cache_read_input_tokens??0)+KA.output_tokens:0,queryChainId:D,queryDepth:H.depth}),!E?.compacted)E={compacted:!0,turnId:I79(),turnCounter:0};let CA=[$.boundaryMarker,...$.summaryMessages,...$.attachments,...$.hookResults,...$.messagesToKeep??[]];for(let yA of CA)yield yA;F=CA}Y={...Y,messages:F};let L=[],O=[];h6("query_setup_start");let _=lw("tengu_streaming_tool_execution2")?new xF1(Y.options.tools,Z,Y):null,j=await Y.getAppState(),P=j.toolPermissionContext.mode,k=z0A({permissionMode:P,mainLoopModel:Y.options.mainLoopModel,exceeds200kTokens:P==="plan"&&a31(F)}),x=s59(Q,G);h6("query_setup_end");let m=void 0,{isAtBlockingLimit:u}=fd(OI(F));if(u){yield RY({content:Qo,error:"invalid_request"});return}let t=!0;h6("query_api_loop_start");try{while(t){t=!1;try{let s=!1;h6("query_api_streaming_start");for await(let FA of jDA({messages:e6A(F,B),systemPrompt:x,maxThinkingTokens:Y.options.maxThinkingTokens,tools:Y.options.tools,signal:Y.abortController.signal,options:{async getToolPermissionContext(){return(await Y.getAppState()).toolPermissionContext},model:k,toolChoice:void 0,isNonInteractiveSession:Y.options.isNonInteractiveSession,fallbackModel:X,onStreamingFallback:()=>{s=!0},querySource:W,agents:Y.options.agentDefinitions.activeAgents,hasAppendSystemPrompt:!!Y.options.appendSystemPrompt,maxOutputTokensOverride:K,fetchOverride:m,mcpTools:j.mcp.tools,queryTracking:H,taskIntensityOverride:m4A(),agentId:Y.agentId}})){if(s){for(let KA of L)yield{type:"tombstone",message:KA};if(l("tengu_orphaned_messages_tombstoned",{orphanedMessageCount:L.length,queryChainId:D,queryDepth:H.depth}),L.length=0,O.length=0,_)_.discard(),_=new xF1(Y.options.tools,Z,Y)}if(yield FA,FA.type==="assistant"){if(L.push(FA),_){let KA=FA.message.content.filter((CA)=>CA.type==="tool_use");for(let CA of KA)_.addTool(CA,FA)}}if(_){for(let KA of _.getCompletedResults())if(KA.message)yield KA.message,O.push(...ZJ([KA.message],Y.options.tools).filter((CA)=>CA.type==="user"))}}h6("query_api_streaming_end")}catch(s){if(s instanceof c31&&X){k=X,t=!0,yield*BM0(L,"Model fallback triggered"),L.length=0,Y.options.mainLoopModel=X,l("tengu_model_fallback_triggered",{original_model:s.originalModel,fallback_model:X,entrypoint:"cli",queryChainId:D,queryDepth:H.depth}),yield ZS(`Model fallback triggered: switching from ${s.originalModel} to ${s.fallbackModel}`,"info");continue}throw s}}}catch(s){r(s instanceof Error?s:Error(String(s)));let FA=s instanceof Error?s.message:String(s);l("tengu_query_error",{assistantMessages:L.length,toolUses:L.flatMap((KA)=>KA.message.content.filter((CA)=>CA.type==="tool_use")).length,queryChainId:D,queryDepth:H.depth}),yield*BM0(L,FA),yield AhA({toolUse:!1}),oO("Query error",s);return}if(L.length>0)Z79([...F,...L],Q,B,G,Y,W);if(L.some((s)=>s.message.content.some((FA)=>FA.type==="text"&&o19(FA.text))))l("tengu_model_response_keyword_detected",{is_overly_agreeable:!0,queryChainId:D,queryDepth:H.depth});if(Y.abortController.signal.aborted){if(_){for await(let s of _.getRemainingResults())if(s.message)yield s.message}else yield*BM0(L,"Interrupted by user");yield AhA({toolUse:!1});return}let b=L.flatMap((s)=>s.message.content.filter((FA)=>FA.type==="tool_use"));if(!L.length||!b.length){if(L[L.length-1]?.apiError==="max_output_tokens"&&V<rG7){let FA=N0({content:"Your response was cut off because it exceeded the output token limit. Please break your work into smaller pieces. Continue from where you left off.",isMeta:!0});yield*yN({messages:[...F,...L,FA],systemPrompt:Q,userContext:B,systemContext:G,canUseTool:Z,toolUseContext:Y,autoCompactTracking:E,fallbackModel:X,querySource:W,maxOutputTokensRecoveryCount:V+1});return}yield*tG7(F,L,Q,B,G,Z,Y,W,E,X,I),yield*sG7(F,L,Q,B,G,Z,Y,W,E,X);return}let p=!1,AA=Y;if(h6("query_tool_execution_start"),_){l("tengu_streaming_tool_execution_used",{tool_count:b.length,queryChainId:D,queryDepth:H.depth});for await(let s of _.getRemainingResults()){let FA=s.message;if(!FA)continue;if(yield FA,FA&&FA.type==="attachment"&&FA.attachment.type==="hook_stopped_continuation")p=!0;O.push(...ZJ([FA],Y.options.tools).filter((KA)=>KA.type==="user"))}AA={..._.getUpdatedContext(),queryTracking:H}}else{l("tengu_streaming_tool_execution_not_used",{tool_count:b.length,queryChainId:D,queryDepth:H.depth});for await(let s of kL0(b,L,Z,Y)){if(s.message){if(yield s.message,s.message.type==="attachment"&&s.message.attachment.type==="hook_stopped_continuation")p=!0;O.push(...ZJ([s.message],Y.options.tools).filter((FA)=>FA.type==="user"))}if(s.newContext)AA={...s.newContext,queryTracking:H}}}if(h6("query_tool_execution_end"),Y.abortController.signal.aborted){yield AhA({toolUse:!0});return}if(p)return;if(E?.compacted)E.turnCounter++,l("tengu_post_autocompact_turn",{turnId:E.turnId,turnCounter:E.turnCounter,queryChainId:D,queryDepth:H.depth});let OA=[...(await AA.getAppState()).queuedCommands],RA=[];l("tengu_query_before_attachments",{messagesForQueryCount:F.length,assistantMessagesCount:L.length,toolResultsCount:O.length,queryChainId:D,queryDepth:H.depth});for await(let s of RDA(null,AA,null,OA,[...F,...L,...O],W))if(yield s,O.push(s),ZW1(s))RA.push(s);let SA=O.filter((s)=>s.type==="attachment"&&s.attachment.type==="edited_text_file").length;l("tengu_query_after_attachments",{totalToolResultsCount:O.length,fileChangeAttachmentCount:SA,queryChainId:D,queryDepth:H.depth});let xA=OA.filter((s)=>s.mode==="prompt");v22(xA,AA.setAppState);let hA={...AA,pendingSteeringAttachments:RA.length>0?RA:void 0,queryTracking:H};h6("query_recursive_call"),yield*yN({messages:[...F,...L,...O],systemPrompt:Q,userContext:B,systemContext:G,canUseTool:Z,toolUseContext:hA,autoCompactTracking:E,fallbackModel:X,stopHookActive:I,querySource:W})}async function*sG7(A,Q,B,G,Z,Y,J,X,I,W){if(J.pendingSteeringAttachments&&J.pendingSteeringAttachments.length>0){let K=[];for(let V of J.pendingSteeringAttachments){let H=V.attachment;if(H.type==="queued_command"){let D=N0({content:H.prompt,isMeta:!0});K.push(D)}}if(K.length>0){let V={...J,pendingSteeringAttachments:void 0};l("tengu_steering_attachment_resending",{queryChainId:J.queryTracking?.chainId,queryDepth:J.queryTracking?.depth}),yield*yN({messages:[...A,...Q,...K],systemPrompt:B,userContext:G,systemContext:Z,canUseTool:Y,toolUseContext:V,autoCompactTracking:I,fallbackModel:W,querySource:X})}return}}async function*tG7(A,Q,B,G,Z,Y,J,X,I,W,K){let V=Date.now(),H={messages:[...A,...Q],systemPrompt:B,userContext:G,systemContext:Z,toolUseContext:J,querySource:X};if(X79(H),process.env.CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION!=="false")V79(H);try{let D=[],E=(await J.getAppState()).toolPermissionContext.mode,z=KM0(E,J.abortController.signal,void 0,K??!1,J.agentId,J,[...A,...Q]),$="",L=0,O=!1,M="",_=!1,j=[],P=[];for await(let k of z){if(k.message){if(yield k.message,k.message.type==="progress"&&k.message.toolUseID){$=k.message.toolUseID,L++;let x=k.message.data;if(x.command)P.push({command:x.command,promptText:x.promptText})}if(k.message.type==="attachment"){let x=k.message.attachment;if("hookEvent"in x&&(x.hookEvent==="Stop"||x.hookEvent==="SubagentStop")){if(x.type==="hook_non_blocking_error")j.push(x.stderr||`Exit code ${x.exitCode}`),_=!0;else if(x.type==="hook_error_during_execution")j.push(x.content),_=!0;else if(x.type==="hook_success"){if(x.stdout&&x.stdout.trim()||x.stderr&&x.stderr.trim())_=!0}}}}if(k.blockingError){let x=N0({content:JM0(k.blockingError),isMeta:!0});D.push(x),yield x,_=!0,j.push(k.blockingError.blockingError)}if(k.preventContinuation)O=!0,M=k.stopReason||"Stop hook prevented continuation",yield o9({type:"hook_stopped_continuation",message:M,hookName:"Stop",toolUseID:$,hookEvent:"Stop"});if(J.abortController.signal.aborted){l("tengu_pre_stop_hooks_cancelled",{queryChainId:J.queryTracking?.chainId,queryDepth:J.queryTracking?.depth}),yield AhA({toolUse:!1});return}}if(L>0){if(yield D79(L,P,j,O,M,_,"suggestion",$),j.length>0)J.addNotification?.({key:"stop-hook-error",text:"Stop hook error occurred · ctrl+o to see",priority:"immediate"})}if(O)return;if(D.length>0)yield*yN({messages:[...A,...Q,...D],systemPrompt:B,userContext:G,systemContext:Z,canUseTool:Y,toolUseContext:J,autoCompactTracking:I,fallbackModel:W,stopHookActive:!0,querySource:X})}catch(D){let F=Date.now()-V;l("tengu_stop_hook_error",{duration:F,queryChainId:J.queryTracking?.chainId,queryDepth:J.queryTracking?.depth}),yield ZS(`Stop hook failed: ${D instanceof Error?D.message:String(D)}`,"warning")}}async function*kL0(A,Q,B,G){let Z=G;for(let{isConcurrencySafe:Y,blocks:J}of eG7(A,Z))if(Y){let X={};for await(let I of QZ7(J,Q,B,Z)){if(I.contextModifier){let{toolUseID:W,modifyContext:K}=I.contextModifier;if(!X[W])X[W]=[];X[W].push(K)}yield{message:I.message,newContext:Z}}for(let I of J){let W=X[I.id];if(!W)continue;for(let K of W)Z=K(Z)}yield{newContext:Z}}else for await(let X of AZ7(J,Q,B,Z)){if(X.newContext)Z=X.newContext;yield{message:X.message,newContext:Z}}}function eG7(A,Q){return A.reduce((B,G)=>{let Z=Q.options.tools.find((X)=>X.name===G.name),Y=Z?.inputSchema.safeParse(G.input),J=Y?.success?Boolean(Z?.isConcurrencySafe(Y.data)):!1;if(J&&B[B.length-1]?.isConcurrencySafe)B[B.length-1].blocks.push(G);else B.push({isConcurrencySafe:J,blocks:[G]});return B},[])}async function*AZ7(A,Q,B,G){let Z=G;for(let Y of A){G.setInProgressToolUseIDs((J)=>new Set([...J,Y.id]));for await(let J of yF1(Y,Q.find((X)=>X.message.content.some((I)=>I.type==="tool_use"&&I.id===Y.id)),B,Z)){if(J.contextModifier)Z=J.contextModifier.modifyContext(Z);yield{message:J.message,newContext:Z}}K79(G,Y.id)}}async function*QZ7(A,Q,B,G){yield*MFA(A.map(async function*(Z){G.setInProgressToolUseIDs((Y)=>new Set([...Y,Z.id])),yield*yF1(Z,Q.find((Y)=>Y.message.content.some((J)=>J.type==="tool_use"&&J.id===Z.id)),B,G),K79(G,Z.id)}),oG7())}function K79(A,Q){A.setInProgressToolUseIDs((B)=>new Set([...B].filter((G)=>G!==Q)))}function BZ7(A,Q){if(!A.startsWith("mcp__"))return;let B=tH(A);if(!B)return;let G=Q.find((Z)=>Y8(Z.name)===B.serverName);if(G?.type==="connected")return G.config.type??"stdio";return}async function*yF1(A,Q,B,G){let Z=A.name,Y=dB1(G.options.tools,Z),J=Q.message.id,X=Q.requestId,I=BZ7(Z,G.options.mcpClients);if(!Y){l("tengu_tool_use_error",{error:`No such tool available: ${Z}`,toolName:Z,toolUseID:A.id,isMcp:Z.startsWith("mcp__"),queryChainId:G.queryTracking?.chainId,queryDepth:G.queryTracking?.depth,...I?{mcpServerType:I}:{},...X?{requestId:X}:{}}),yield{message:N0({content:[{type:"tool_result",content:`<tool_use_error>Error: No such tool available: ${Z}</tool_use_error>`,is_error:!0,tool_use_id:A.id}],toolUseResult:`Error: No such tool available: ${Z}`,sourceToolAssistantUUID:Q.uuid})};return}let W=A.input;try{if(G.abortController.signal.aborted){l("tengu_tool_use_cancelled",{toolName:Y.name,toolUseID:A.id,isMcp:Y.isMcp??!1,queryChainId:G.queryTracking?.chainId,queryDepth:G.queryTracking?.depth,...I?{mcpServerType:I}:{},...X?{requestId:X}:{}});let K=VM0(A.id);yield{message:N0({content:[K],toolUseResult:qFA,sourceToolAssistantUUID:Q.uuid})};return}for await(let K of GZ7(Y,A.id,W,G,B,Q,J,X,I))yield K}catch(K){r(K instanceof Error?K:Error(String(K)));let V=K instanceof Error?K.message:String(K),D=`Error calling tool${Y?` (${Y.name})`:""}: ${V}`;yield{message:N0({content:[{type:"tool_result",content:`<tool_use_error>${D}</tool_use_error>`,is_error:!0,tool_use_id:A.id}],toolUseResult:D,sourceToolAssistantUUID:Q.uuid})}}}function GZ7(A,Q,B,G,Z,Y,J,X,I){let W=new efA;return ZZ7(A,Q,B,G,Z,Y,J,X,I,(K)=>{l("tengu_tool_use_progress",{messageID:J,toolName:A.name,isMcp:A.isMcp??!1,queryChainId:G.queryTracking?.chainId,queryDepth:G.queryTracking?.depth,...I?{mcpServerType:I}:{},...X?{requestId:X}:{}}),W.enqueue({message:H79({toolUseID:K.toolUseID,parentToolUseID:Q,data:K.data})})}).then((K)=>{for(let V of K)W.enqueue(V)}).catch((K)=>{W.error(K)}).finally(()=>{W.done()}),W}async function ZZ7(A,Q,B,G,Z,Y,J,X,I,W){let K=A.inputSchema.safeParse(B);if(!K.success){let j=IZ7(A.name,K.error);return l("tengu_tool_use_error",{error:"InputValidationError",errorDetails:j.slice(0,2000),messageID:J,toolName:A.name,isMcp:A.isMcp??!1,queryChainId:G.queryTracking?.chainId,queryDepth:G.queryTracking?.depth,...I?{mcpServerType:I}:{},...X?{requestId:X}:{}}),[{message:N0({content:[{type:"tool_result",content:`<tool_use_error>InputValidationError: ${j}</tool_use_error>`,is_error:!0,tool_use_id:Q}],toolUseResult:`InputValidationError: ${K.error.message}`,sourceToolAssistantUUID:Y.uuid})}]}let V=await A.validateInput?.(K.data,G);if(V?.result===!1)return l("tengu_tool_use_error",{messageID:J,toolName:A.name,error:V.message,errorCode:V.errorCode,isMcp:A.isMcp??!1,queryChainId:G.queryTracking?.chainId,queryDepth:G.queryTracking?.depth,...I?{mcpServerType:I}:{},...X?{requestId:X}:{}}),[{message:N0({content:[{type:"tool_result",content:`<tool_use_error>${V.message}</tool_use_error>`,is_error:!0,tool_use_id:Q}],toolUseResult:`Error: ${V.message}`,sourceToolAssistantUUID:Y.uuid})}];let H=[],D=K.data,F=!1,E,z;for await(let j of XZ7(G,A,D,Q,Y.message.id,X,I))switch(j.type){case"message":if(j.message.message.type==="progress")W(j.message.message);else H.push(j.message);break;case"hookPermissionResult":z=j.hookPermissionResult;break;case"preventContinuation":F=j.shouldPreventContinuation;break;case"stopReason":E=j.stopReason;break;case"stop":return H.push({message:N0({content:[VM0(Q)],toolUseResult:`Error: ${E}`,sourceToolAssistantUUID:Y.uuid})}),H}let $={};if(D&&typeof D==="object"){if(A.name===p6&&"file_path"in D)$.file_path=String(D.file_path);else if((A.name===x3||A.name===vZ)&&"file_path"in D)$.file_path=String(D.file_path);else if(A.name===H9&&"command"in D){let j=D;$.full_command=j.command}}dF2(A.name,$),pF2();let L;if(z!==void 0&&z.behavior==="allow"&&!A.requiresUserInteraction?.())v(`Hook approved tool use for ${A.name}, bypassing permission check`),L=z;else if(z!==void 0&&z.behavior==="allow"&&A.requiresUserInteraction?.())v(`Hook approved tool use for ${A.name}, but tool requires user interaction`),L=await Z(A,D,G,Y,Q);else if(z!==void 0&&z.behavior==="deny")v(`Hook denied tool use for ${A.name}`),L=z;else{let j=z?.behavior==="ask"?z:void 0;L=await Z(A,D,G,Y,Q,j)}if(L.decisionReason?.type==="hook"&&L.decisionReason.hookName==="PermissionRequest"&&L.behavior!=="ask")H.push({message:o9({type:"hook_permission_decision",decision:L.behavior,toolUseID:Q,hookEvent:"PermissionRequest"})});if(L.behavior!=="allow"){let j=G.toolDecisions?.get(Q);TK0("reject",j?.source||"unknown"),wY1(),l("tengu_tool_use_can_use_tool_rejected",{messageID:J,toolName:A.name,queryChainId:G.queryTracking?.chainId,queryDepth:G.queryTracking?.depth,...I?{mcpServerType:I}:{},...X?{requestId:X}:{}});let P=L.message;if(F&&!P)P=`Execution stopped by PreToolUse hook${E?`: ${E}`:""}`;return H.push({message:N0({content:[{type:"tool_result",content:P,is_error:!0,tool_use_id:Q}],toolUseResult:`Error: ${P}`,sourceToolAssistantUUID:Y.uuid})}),H}l("tengu_tool_use_can_use_tool_allowed",{messageID:J,toolName:A.name,queryChainId:G.queryTracking?.chainId,queryDepth:G.queryTracking?.depth,...I?{mcpServerType:I}:{},...X?{requestId:X}:{}}),D=L.updatedInput;let O={};if(A.name===H9&&"command"in D){let j=D;O={bash_command:j.command.trim().split(/\s+/)[0]||"",full_command:j.command,...j.timeout!==void 0&&{timeout:j.timeout},...j.description!==void 0&&{description:j.description},..."dangerouslyDisableSandbox"in j&&{dangerouslyDisableSandbox:j.dangerouslyDisableSandbox}}}let M=G.toolDecisions?.get(Q);TK0(M?.decision||"unknown",M?.source||"unknown"),cF2();let _=Date.now();try{let j=await A.call(D,{...G,userModified:L.userModified??!1},Z,Y,(p)=>{W({toolUseID:p.toolUseID,data:p.data})}),P=Date.now()-_;if(O$1(P),j.data&&typeof j.data==="object"){let p={};if(A.name===p6&&"content"in j.data){if("file_path"in D)p.file_path=String(D.file_path);p.content=String(j.data.content)}if((A.name===x3||A.name===vZ)&&"file_path"in D){if(p.file_path=String(D.file_path),A.name===x3&&"diff"in j.data)p.diff=String(j.data.diff);if(A.name===vZ&&"content"in D)p.content=String(D.content)}if(A.name===H9&&"command"in D){let AA=D;if(p.bash_command=AA.command,"output"in j.data)p.output=String(j.data.output)}if(Object.keys(p).length>0)lF2("tool.output",p)}if(typeof j==="object"&&"structured_output"in j)H.push({message:o9({type:"structured_output",data:j.structured_output})});PK0({success:!0});let k=j.data&&typeof j.data==="object"?Q1(j.data):String(j.data??"");wY1(k);let x=0;try{x=Q1(j.data).length}catch(p){r(p instanceof Error?p:Error(String(p)))}l("tengu_tool_use_success",{messageID:J,toolName:A.name,isMcp:A.isMcp??!1,durationMs:P,toolResultSizeBytes:x,queryChainId:G.queryTracking?.chainId,queryDepth:G.queryTracking?.depth,...I?{mcpServerType:I}:{},...X?{requestId:X}:{}});let m=i_(A)?GM0(A.name):null;XD("tool_result",{tool_name:A.name,success:"true",duration_ms:String(P),...Object.keys(O).length>0&&{tool_parameters:Q1(O)},tool_result_size_bytes:String(x),...M&&{decision_source:M.source,decision_type:M.decision},...m&&{mcp_server_scope:m}});let u=j.data,t=[],e=j.contextModifier;async function b(p){let ZA=[await PQ2(A,p,Q)];if("acceptFeedback"in L&&L.acceptFeedback)ZA.push({type:"text",text:L.acceptFeedback});H.push({message:N0({content:ZA,toolUseResult:p,sourceToolAssistantUUID:Y.uuid}),contextModifier:e?{toolUseID:Q,modifyContext:e}:void 0})}if(!i_(A))await b(u);for await(let p of YZ7(G,A,Q,Y.message.id,L,u,X,I))if("updatedMCPToolOutput"in p){if(i_(A))u=p.updatedMCPToolOutput}else if(i_(A))t.push(p);else H.push(p);if(i_(A))await b(u);if(j.newMessages&&j.newMessages.length>0)for(let p of j.newMessages)H.push({message:p});if(F)H.push({message:o9({type:"hook_stopped_continuation",message:E||"Execution stopped by hook",hookName:`PreToolUse:${A.name}`,toolUseID:Q,hookEvent:"PreToolUse"})});for(let p of t)H.push(p);return H}catch(j){let P=Date.now()-_;if(O$1(P),PK0({success:!1,error:j instanceof Error?j.message:String(j)}),wY1(),!(j instanceof lY)){if(!(j instanceof Hy))r(j instanceof Error?j:Error(String(j)));l("tengu_tool_use_error",{messageID:J,toolName:A.name,error:j instanceof Error?j.constructor.name:"UnknownError",isMcp:A.isMcp??!1,queryChainId:G.queryTracking?.chainId,queryDepth:G.queryTracking?.depth,...I?{mcpServerType:I}:{},...X?{requestId:X}:{}});let u=i_(A)?GM0(A.name):null;XD("tool_result",{tool_name:A.name,use_id:Q,success:"false",duration_ms:String(P),error:j instanceof Error?j.message:String(j),...Object.keys(O).length>0&&{tool_parameters:Q1(O)},...M&&{decision_source:M.source,decision_type:M.decision},...u&&{mcp_server_scope:u}})}let k=kF1(j),x=j instanceof lY,m=[];for await(let u of JZ7(G,A,Q,J,D,k,x,X,I))m.push(u);return[{message:N0({content:[{type:"tool_result",content:k,is_error:!0,tool_use_id:Q}],toolUseResult:`Error: ${k}`,sourceToolAssistantUUID:Y.uuid})},...m]}finally{if(M)G.toolDecisions?.delete(Q)}}async function*YZ7(A,Q,B,G,Z,Y,J,X){let I=Date.now();try{let K=(await A.getAppState()).toolPermissionContext.mode,V=Y;for await(let H of IM0(Q.name,B,Z.updatedInput,V,A,K,A.abortController.signal))try{if(H.message?.type==="attachment"&&H.message.attachment.type==="hook_cancelled"){l("tengu_post_tool_hooks_cancelled",{toolName:Q.name,queryChainId:A.queryTracking?.chainId,queryDepth:A.queryTracking?.depth}),yield{message:o9({type:"hook_cancelled",hookName:`PostToolUse:${Q.name}`,toolUseID:B,hookEvent:"PostToolUse"})};continue}if(H.message)yield{message:H.message};if(H.blockingError)yield{message:o9({type:"hook_blocking_error",hookName:`PostToolUse:${Q.name}`,toolUseID:B,hookEvent:"PostToolUse",blockingError:H.blockingError})};if(H.preventContinuation){yield{message:o9({type:"hook_stopped_continuation",message:H.stopReason||"Execution stopped by PostToolUse hook",hookName:`PostToolUse:${Q.name}`,toolUseID:B,hookEvent:"PostToolUse"})};return}if(H.additionalContexts&&H.additionalContexts.length>0)yield{message:o9({type:"hook_additional_context",content:H.additionalContexts,hookName:`PostToolUse:${Q.name}`,toolUseID:B,hookEvent:"PostToolUse"})};if(H.updatedMCPToolOutput&&i_(Q))V=H.updatedMCPToolOutput,yield{updatedMCPToolOutput:V}}catch(D){let F=Date.now()-I;l("tengu_post_tool_hook_error",{messageID:G,toolName:Q.name,isMcp:Q.isMcp??!1,duration:F,queryChainId:A.queryTracking?.chainId,queryDepth:A.queryTracking?.depth,...X?{mcpServerType:X}:{},...J?{requestId:J}:{}}),yield{message:o9({type:"hook_error_during_execution",content:kF1(D),hookName:`PostToolUse:${Q.name}`,toolUseID:B,hookEvent:"PostToolUse"})}}}catch(W){r(W instanceof Error?W:Error(String(W)))}}async function*JZ7(A,Q,B,G,Z,Y,J,X,I){let W=Date.now();try{let V=(await A.getAppState()).toolPermissionContext.mode;for await(let H of WM0(Q.name,B,Z,Y,A,J,V,A.abortController.signal))try{if(H.message?.type==="attachment"&&H.message.attachment.type==="hook_cancelled"){l("tengu_post_tool_failure_hooks_cancelled",{toolName:Q.name,queryChainId:A.queryTracking?.chainId,queryDepth:A.queryTracking?.depth}),yield{message:o9({type:"hook_cancelled",hookName:`PostToolUseFailure:${Q.name}`,toolUseID:B,hookEvent:"PostToolUseFailure"})};continue}if(H.message)yield{message:H.message};if(H.blockingError)yield{message:o9({type:"hook_blocking_error",hookName:`PostToolUseFailure:${Q.name}`,toolUseID:B,hookEvent:"PostToolUseFailure",blockingError:H.blockingError})};if(H.additionalContexts&&H.additionalContexts.length>0)yield{message:o9({type:"hook_additional_context",content:H.additionalContexts,hookName:`PostToolUseFailure:${Q.name}`,toolUseID:B,hookEvent:"PostToolUseFailure"})}}catch(D){let F=Date.now()-W;l("tengu_post_tool_failure_hook_error",{messageID:G,toolName:Q.name,isMcp:Q.isMcp??!1,duration:F,queryChainId:A.queryTracking?.chainId,queryDepth:A.queryTracking?.depth,...I?{mcpServerType:I}:{},...X?{requestId:X}:{}}),yield{message:o9({type:"hook_error_during_execution",content:kF1(D),hookName:`PostToolUseFailure:${Q.name}`,toolUseID:B,hookEvent:"PostToolUseFailure"})}}}catch(K){r(K instanceof Error?K:Error(String(K)))}}async function*XZ7(A,Q,B,G,Z,Y,J){let X=Date.now();try{let I=await A.getAppState();for await(let W of XM0(Q.name,G,B,A,I.toolPermissionContext.mode,A.abortController.signal))try{if(W.message)yield{type:"message",message:{message:W.message}};if(W.blockingError){let K=YM0(`PreToolUse:${Q.name}`,W.blockingError);yield{type:"hookPermissionResult",hookPermissionResult:{behavior:"deny",message:K,decisionReason:{type:"hook",hookName:`PreToolUse:${Q.name}`,reason:K}}}}if(W.preventContinuation){if(yield{type:"preventContinuation",shouldPreventContinuation:!0},W.stopReason)yield{type:"stopReason",stopReason:W.stopReason}}if(W.permissionBehavior!==void 0){v(`Hook result has permissionBehavior=${W.permissionBehavior}`);let K={type:"hook",hookName:`PreToolUse:${Q.name}`,reason:W.hookPermissionDecisionReason};if(W.permissionBehavior==="allow")yield{type:"hookPermissionResult",hookPermissionResult:{behavior:"allow",updatedInput:W.updatedInput||B,decisionReason:K}};else yield{type:"hookPermissionResult",hookPermissionResult:{behavior:W.permissionBehavior,message:W.hookPermissionDecisionReason||`Hook PreToolUse:${Q.name} ${tMB(W.permissionBehavior)} this tool`,decisionReason:K}}}if(A.abortController.signal.aborted){l("tengu_pre_tool_hooks_cancelled",{toolName:Q.name,queryChainId:A.queryTracking?.chainId,queryDepth:A.queryTracking?.depth}),yield{type:"message",message:{message:o9({type:"hook_cancelled",hookName:`PreToolUse:${Q.name}`,toolUseID:G,hookEvent:"PreToolUse"})}},yield{type:"stop"};return}}catch(K){r(K instanceof Error?K:Error(String(K)));let V=Date.now()-X;l("tengu_pre_tool_hook_error",{messageID:Z,toolName:Q.name,isMcp:Q.isMcp??!1,duration:V,queryChainId:A.queryTracking?.chainId,queryDepth:A.queryTracking?.depth,...J?{mcpServerType:J}:{},...Y?{requestId:Y}:{}}),yield{type:"message",message:{message:o9({type:"hook_error_during_execution",content:kF1(K),hookName:`PreToolUse:${Q.name}`,toolUseID:G,hookEvent:"PreToolUse"})}},yield{type:"stop"}}}catch(I){r(I instanceof Error?I:Error(String(I))),yield{type:"stop"};return}}function kF1(A){if(A instanceof lY)return A.message||b_;if(!(A instanceof Error))return String(A);let B=ZM0(A).filter(Boolean).join(`
RangeError: Maximum call stack size exceeded
(Use `node --trace-uncaught ...` to show where the exception was thrown)
Node.js v22.14.0
Steps to Reproduce
- Have a well specified CLAUDE.md
- Do some complex work in Rust requiring significant context
- Integrate an external tool like git into your workflow
- Wait for it to eventually crash out trying to prepare a git commit
- Also fails with other tools like attempting mass-updates, deep searches, etc.
Claude Model
Opus
Is this a regression?
Yes, this worked in a previous version
Last Working Version
anything pre 2.1.2
Claude Code Version
2.1.2
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Warp
Additional Information
For context, my terminal is Warp, this is running on an updated MacOs.
However, I have confirmed the crashes still occur using native MacOs Terminal or IDE terminals (RustRover in this case).
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗