zed-industries/zed · error
tool input was not fully received
Error message
tool input was not fully received
What it means
ToolInputReceiver::recv awaits the fully deserialized tool input and returns this error when the payload stream ends without ever delivering ToolInputPayload::Full. The underlying mpsc channel closes when the producer (the streaming tool-call input) is dropped, which happens on turn cancellation, stream termination, or provider failure.
Source
Thrown at crates/agent/src/thread.rs:4991
#[cfg(any(test, feature = "test-support"))]
pub fn test() -> (ToolInputSender, Self) {
let (sender, input) = ToolInputSender::channel();
(sender, input.cast())
}
/// Wait for the final deserialized input, ignoring all partial updates.
/// Non-streaming tools can use this to wait until the whole input is available.
pub async fn recv(mut self) -> Result<T> {
while let Ok(value) = self.next().await {
match value {
ToolInputPayload::Full(value) => return Ok(value),
ToolInputPayload::Partial(_) => {}
ToolInputPayload::InvalidJson { error_message } => {
return Err(anyhow!(error_message));
}
}
}
Err(anyhow!("tool input was not fully received"))
}
pub async fn next(&mut self) -> Result<ToolInputPayload<T>> {
let value = self
.rx
.next()
.await
.ok_or_else(|| anyhow!("tool input was not fully received"))?;
Ok(match value {
ToolInputPayload::Partial(payload) => ToolInputPayload::Partial(payload),
ToolInputPayload::Full(payload) => {
ToolInputPayload::Full(serde_json::from_value(payload)?)
}
ToolInputPayload::InvalidJson { error_message } => {
ToolInputPayload::InvalidJson { error_message }
}
})View on GitHub (pinned to bc538def45)
Solutions
- Check whether the thread or turn was cancelled and treat the error as expected in that case
- Retry the prompt or request if no cancellation happened; truncated streams are usually transient
- If it recurs with one provider, switch providers or report it, since complete tool inputs should always arrive
- Ensure tools surface this error instead of unwrap-ing the receiver
Example fix
// before
let input = receiver.recv().await?;
// after
let input = match receiver.recv().await {
Ok(input) => input,
Err(err) if turn_was_cancelled() => return Ok(()), // stopping mid-stream is fine
Err(err) => {
log::warn!("tool input incomplete: {err}");
return Err(err);
}
}; Defensive patterns
Strategy: try-catch
Try / catch
let input = match receiver.recv().await {
Ok(input) => input,
Err(err) if turn_was_cancelled() => return Ok(()), // expected on stop
Err(err) => {
log::warn!("tool input incomplete: {err}");
return Err(err); // non-cancelled truncation: surface to the turn
}
}; Prevention
- Stop consuming the receiver once the turn is cancelled; a cancelled producer closes the channel without a Full payload
- Consume the receiver to completion or drop it deliberately; never poll after the turn ended
- Prefer recv() for non-streaming tools so partial fragments cannot be mistaken for complete input
- Watch provider stream health; recurring truncation indicates a provider or network fault
When it happens
Trigger: The turn is cancelled while a streaming tool call is still emitting partial JSON; the provider ends the response stream mid tool-call without a complete input; or the producer task is dropped due to an upstream error, closing the channel with no Full payload sent.
Common situations: User presses stop during a long tool-argument stream; a network drop truncates the model stream; a provider bug closes the stream without finishing the tool call.
Related errors
- authorization channel closed
- Failed to send tool call decision prompt: {error}
- User canceled
- The agent is nearing the end of its context window and has b
- Attempted to read an image, but this model doesn't support i
AI-assisted analysis of zed-industries/zed@bc538def45 (2026-08-16).
Data as JSON: /api/errors/885c3a500d0938f2.
Report an issue: GitHub.