Cursor SDK run.stream messages do not receive 'error' status messages for tool_calls

Where does the bug appear (feature/product)?

Somewhere else…

Describe the Bug

I am using @cursorcursor/sdk to run an agent and processing the stream event to be showing in my app to see what’s going on using run.stream() and iterating over messages. It seems that when agent decides to use read tool to read a file that does not exist, there is no expected “error” status tool_call message received in the stream, only the first one with “running” state. This means, that the UI that’s showing the messages never gets the information that file could not be read. The same applies when trying to use onDelta/onStep callbacks - only “running” state messages are received. I have also noticed the same behavior with some other tools such as grep or glob.

Here are some traces where I told the agent to read non-existent file. You can see glob tool used but no ‘error’ or ‘completed’ status sent and also read tool. message log is from within the runStream loop, onDelta/onStep from the callback):

onDelta {
  type: 'tool-call-started',
  callId: 'tool_814c01df-c634-4d36-b756-ad20785a43a',
  toolCall: {
    type: 'glob',
    args: {
      globPattern: '**/QUICK_START_GUIDE.cs',
      targetDirectory: '/path/to/my/project'
    }
  },
  modelCallId: 'f8d36a2c-e2c9-4677-a10b-552a96812961-0-ndmx'
}
message {
  type: 'tool_call',
  agent_id: 'agent-eae76da5-4fc5-478f-b724-9dcd4021ba2f',
  run_id: 'run-d1f51280-ae82-48e4-9d93-56a9ba008784',
  call_id: 'tool_814c01df-c634-4d36-b756-ad20785a43a',
  name: 'glob',
  status: 'running',
  args: {
    globPattern: '**/QUICK_START_GUIDE.cs',
    targetDirectory: '/path/to/my/project'
  }
}
onDelta { type: 'token-delta', tokens: 17 }
onDelta { type: 'token-delta', tokens: 3 }
onDelta { type: 'token-delta', tokens: 26 }
onDelta { type: 'token-delta', tokens: 4 }
onDelta { type: 'token-delta', tokens: 10 }
onDelta {
  type: 'tool-call-started',
  callId: 'tool_aea5cc06-22cd-45fa-8120-fd0fabfb092',
  toolCall: {
    type: 'shell',
    args: {
      command: "find /path/to/my/project -name 'QUICK_START_GUIDE.cs' 2>/dev/null",
      timeout: 30000
    }
  },
  modelCallId: 'f8d36a2c-e2c9-4677-a10b-552a96812961-1-ndyw'
}
message {
  type: 'tool_call',
  agent_id: 'agent-eae76da5-4fc5-478f-b724-9dcd4021ba2f',
  run_id: 'run-d1f51280-ae82-48e4-9d93-56a9ba008784',
  call_id: 'tool_aea5cc06-22cd-45fa-8120-fd0fabfb092',
  name: 'shell',
  status: 'running',
  args: {
    command: "find /path/to/my/project -name 'QUICK_START_GUIDE.cs' 2>/dev/null",
    timeout: 30000
  }
}
onStep {
  type: 'toolCall',
  message: {
    type: 'shell',
    args: {
      command: "find /path/to/my/project -name 'QUICK_START_GUIDE.cs' 2>/dev/null",
      timeout: 30000
    },
    result: { status: 'success', value: [Object] }
  }
}
onDelta {
  type: 'tool-call-completed',
  callId: 'tool_aea5cc06-22cd-45fa-8120-fd0fabfb092',
  toolCall: {
    type: 'shell',
    args: {
      command: "find /path/to/my/project -name 'QUICK_START_GUIDE.cs' 2>/dev/null",
      timeout: 30000
    },
    result: { status: 'success', value: [Object] }
  },
  modelCallId: 'f8d36a2c-e2c9-4677-a10b-552a96812961-1-ndyw'
}
message {
  type: 'tool_call',
  agent_id: 'agent-eae76da5-4fc5-478f-b724-9dcd4021ba2f',
  run_id: 'run-d1f51280-ae82-48e4-9d93-56a9ba008784',
  call_id: 'tool_aea5cc06-22cd-45fa-8120-fd0fabfb092',
  name: 'shell',
  status: 'completed',
  args: {
    command: "find /path/to/my/project -name 'QUICK_START_GUIDE.cs' 2>/dev/null",
    timeout: 30000
  },
  result: {
    status: 'success',
    value: {
      exitCode: 0,
      signal: '',
      stdout: '',
      stderr: '--: cannot set uid to 1000: effective uid 1000: Operation not permitted\n',
      executionTime: 658
    }
  }
}
onDelta { type: 'token-delta', tokens: 50 }
onDelta { type: 'token-delta', tokens: 2 }
onDelta { type: 'token-delta', tokens: 14 }
onDelta { type: 'token-delta', tokens: 4 }
onDelta { type: 'token-delta', tokens: 5 }
onDelta {
  type: 'tool-call-started',
  callId: 'tool_4453a570-04c5-40fe-a674-5e987640b79',
  toolCall: {
    type: 'grep',
    args: {
      pattern: 'QUICK_START_GUIDE',
      path: '/path/to/my/project',
      offset: 0
    }
  },
  modelCallId: 'f8d36a2c-e2c9-4677-a10b-552a96812961-2-ztbi'
}
message {
  type: 'tool_call',
  agent_id: 'agent-eae76da5-4fc5-478f-b724-9dcd4021ba2f',
  run_id: 'run-d1f51280-ae82-48e4-9d93-56a9ba008784',
  call_id: 'tool_4453a570-04c5-40fe-a674-5e987640b79',
  name: 'grep',
  status: 'running',
  args: {
    pattern: 'QUICK_START_GUIDE',
    path: '/path/to/my/project',
    offset: 0
  }
}
onDelta { type: 'token-delta', tokens: 22 }
onDelta { type: 'token-delta', tokens: 2 }
onDelta { type: 'token-delta', tokens: 20 }
onDelta {
  type: 'tool-call-started',
  callId: 'tool_6097697e-2da0-4ea7-93be-66dcf96b1d9',
  toolCall: {
    type: 'read',
    args: {
      path: '/path/to/my/project/QUICK_START_GUIDE.cs'
    }
  },
  modelCallId: 'f8d36a2c-e2c9-4677-a10b-552a96812961-3-m2zj'
}
message {
  type: 'tool_call',
  agent_id: 'agent-eae76da5-4fc5-478f-b724-9dcd4021ba2f',
  run_id: 'run-d1f51280-ae82-48e4-9d93-56a9ba008784',
  call_id: 'tool_6097697e-2da0-4ea7-93be-66dcf96b1d9',
  name: 'read',
  status: 'running',
  args: {
    path: '/path/to/my/project/QUICK_START_GUIDE.cs'
  }
}
onDelta { type: 'token-delta', tokens: 5 }
onDelta { type: 'token-delta', tokens: 3 }
onDelta { type: 'token-delta', tokens: 48 }
onDelta { type: 'token-delta', tokens: 5 }
onDelta { type: 'token-delta', tokens: 10 }
onDelta {
  type: 'tool-call-started',
  callId: 'tool_a0aa8e40-ed2f-45a0-9769-4520572283b',
  toolCall: {
    type: 'shell',
    args: {
      command: 'ls -la /path/to/my/project/*.cs 2>/dev/null; ls -la /path/to/my/project/**/QUICK_START_GUIDE.cs 2>/dev/null | head -20',
      timeout: 30000
    }
  },
  modelCallId: 'f8d36a2c-e2c9-4677-a10b-552a96812961-4-owu2'
}
message {
  type: 'tool_call',
  agent_id: 'agent-eae76da5-4fc5-478f-b724-9dcd4021ba2f',
  run_id: 'run-d1f51280-ae82-48e4-9d93-56a9ba008784',
  call_id: 'tool_a0aa8e40-ed2f-45a0-9769-4520572283b',
  name: 'shell',
  status: 'running',
  args: {
    command: 'ls -la /path/to/my/project/*.cs 2>/dev/null; ls -la /path/to/my/project/**/QUICK_START_GUIDE.cs 2>/dev/null | head -20',
    timeout: 30000
  }
}
onStep {
  type: 'toolCall',
  message: {
    type: 'shell',
    args: {
      command: 'ls -la /path/to/my/project/*.cs 2>/dev/null; ls -la /path/to/my/project/**/QUICK_START_GUIDE.cs 2>/dev/null | head -20',
      timeout: 30000
    },
    result: { status: 'success', value: [Object] }
  }
}
onDelta {
  type: 'tool-call-completed',
  callId: 'tool_a0aa8e40-ed2f-45a0-9769-4520572283b',
  toolCall: {
    type: 'shell',
    args: {
      command: 'ls -la /path/to/my/project/*.cs 2>/dev/null; ls -la /path/to/my/project/**/QUICK_START_GUIDE.cs 2>/dev/null | head -20',
      timeout: 30000
    },
    result: { status: 'success', value: [Object] }
  },
  modelCallId: 'f8d36a2c-e2c9-4677-a10b-552a96812961-4-owu2'
}
message {
  type: 'tool_call',
  agent_id: 'agent-eae76da5-4fc5-478f-b724-9dcd4021ba2f',
  run_id: 'run-d1f51280-ae82-48e4-9d93-56a9ba008784',
  call_id: 'tool_a0aa8e40-ed2f-45a0-9769-4520572283b',
  name: 'shell',
  status: 'completed',
  args: {
    command: 'ls -la /path/to/my/project/*.cs 2>/dev/null; ls -la /path/to/my/project/**/QUICK_START_GUIDE.cs 2>/dev/null | head -20',
    timeout: 30000
  },
  result: {
    status: 'success',
    value: {
      exitCode: 2,
      signal: '',
      stdout: '',
      stderr: '--: cannot set uid to 1000: effective uid 1000: Operation not permitted\n',
      executionTime: 351
    }
  }
}
...

Steps to Reproduce

Ask agent to read file that does not exist and see the agent stream messages.

Expected Behavior

When tool has error, I expect tool_call message with ‘error’ status to be received in the stream.

Operating System

Linux

Version Information

@cursor/[email protected]

For AI issues: which model did you use?

composer-2

Does this stop you from using Cursor

No - Cursor works, but with this issue

This is a confirmed bug. As a workaround, you can detect tool call completions by watching for the next tool call or text delta arriving after a running tool call, since the agent moves on once the tool has finished. It’s not clean, but it’s functional until the fix ships.

We’re tracking this for a fix on our side. The issue is in how the agent execution layer emits interaction updates for synchronously-executed tools.