zed-industries/zed · error
Terminal with id `{}` not found
Error message
Terminal with id `{}` not found What it means
Converting acp::ToolCallContent::Terminal into the local representation requires the terminal_id to be present in the terminals map passed to the conversion. When the referenced terminal is not tracked there, conversion fails with the missing id.
Source
Thrown at crates/acp_thread/src/acp_thread.rs:1844
&language_registry,
path_style,
cx,
)),
)),
acp::ToolCallContent::Diff(diff) => Ok(Some(Self::Diff(cx.new(|cx| {
Diff::finalized(
diff.path.to_string_lossy().into_owned(),
diff.old_text,
diff.new_text,
language_registry,
cx,
)
})))),
acp::ToolCallContent::Terminal(acp::Terminal { terminal_id, .. }) => terminals
.get(&terminal_id)
.cloned()
.map(|terminal| Some(Self::Terminal(terminal)))
.ok_or_else(|| anyhow::anyhow!("Terminal with id `{}` not found", terminal_id)),
_ => Ok(None),
}
}
pub fn update_from_acp(
&mut self,
new: acp::ToolCallContent,
language_registry: Arc<LanguageRegistry>,
path_style: PathStyle,
terminals: &HashMap<acp::TerminalId, Entity<Terminal>>,
cx: &mut App,
) -> Result<bool> {
// Update streaming text in place so the rendered markdown element is
// reused across snapshots instead of being recreated (which flickers).
if let (
Self::ContentBlock(block),
acp::ToolCallContent::Content(acp::Content { content, .. }),
) = (&mut *self, &new)View on GitHub (pinned to bc538def45)
Solutions
- Populate the terminals map (keyed by acp::TerminalId) before forwarding or replaying tool-call content that references terminals.
- When an unknown id is seen, defer or drop that content block instead of failing the entire conversion.
- When replaying persisted threads, recreate terminals under their persisted ids or strip Terminal blocks first.
Example fix
// before
let content = ToolCallContent::from_acp(raw, registry, path_style, &terminals, cx)?; // fails on unknown id
// after
if let acp::ToolCallContent::Terminal(t) = &raw {
if !terminals.contains_key(&t.terminal_id) {
return Ok(None); // skip block instead of erroring
}
}
let content = ToolCallContent::from_acp(raw, registry, path_style, &terminals, cx)?; Defensive patterns
Strategy: validation
Validate before calling
if let acp::ToolCallContent::Terminal(acp::Terminal { terminal_id, .. }) = &content {
if !terminals.contains_key(terminal_id) {
// skip or defer this block; do not attempt conversion
return Ok(None);
}
} Type guard
fn terminal_is_tracked(
terminal_id: &acp::TerminalId,
terminals: &HashMap<acp::TerminalId, Entity<Terminal>>,
) -> bool {
terminals.contains_key(terminal_id)
} Try / catch
match ToolCallContent::from_acp(raw, registry, path_style, &terminals, cx) {
Ok(content) => { /* render */ }
Err(e) if e.to_string().starts_with("Terminal with id") => {
// unknown terminal: drop the block, keep the rest of the tool call
}
Err(e) => return Err(e),
} Prevention
- Register terminals in the map before replaying tool-call content that references them.
- When replaying persisted threads, recreate terminals by persisted id or strip Terminal blocks.
When it happens
Trigger: A tool-call content event referencing a terminal id that was never registered in the HashMap — events arriving before the terminal is created, from another window, or after the terminal was removed; replaying persisted threads whose terminals were not restored.
Common situations: Deserializing recorded/replayed sessions without recreating terminals; ordering races between terminal creation and tool-call content events; multi-window setups.
Related errors
- output token limit reached
- message not found
- not supported
- cannot capture writable sandbox path `{}`
- no thread found with ID: {id:?}
AI-assisted analysis of zed-industries/zed@bc538def45 (2026-08-16).
Data as JSON: /api/errors/4b744b2e830d5396.
Report an issue: GitHub.