zeroclaw-labs/zeroclaw · error
Telegram attachment path not found: {target}
Error message
Telegram attachment path not found: {target} What it means
Before uploading an attachment, send_attachment remaps Docker-style /workspace/... paths onto the configured host workspace_dir, then requires the resulting path to exist; otherwise it bails with the (possibly still-remapped) target. This is a host/container filesystem mismatch or missing-file guard, not a Telegram API error.
Source
Thrown at crates/zeroclaw-channels/src/telegram.rs:3127
// Remap Docker container workspace path (/workspace/...) to the host
// workspace directory so files written by the containerised runtime
// can be found and sent by the host-side Telegram sender.
let remapped;
let target = if let Some(rel) = target.strip_prefix("/workspace/") {
if let Some(ws) = &self.workspace_dir {
remapped = ws.join(rel);
remapped.to_str().unwrap_or(target)
} else {
target
}
} else {
target
};
let path = Path::new(target);
if !path.exists() {
anyhow::bail!("Telegram attachment path not found: {target}");
}
match attachment.kind {
TelegramAttachmentKind::Image => self.send_photo(chat_id, thread_id, path, None).await,
TelegramAttachmentKind::Document => {
self.send_document(chat_id, thread_id, path, None).await
}
TelegramAttachmentKind::Video => self.send_video(chat_id, thread_id, path, None).await,
TelegramAttachmentKind::Audio => self.send_audio(chat_id, thread_id, path, None).await,
TelegramAttachmentKind::Voice => self.send_voice(chat_id, thread_id, path, None).await,
}
}
/// Send a document/file to a Telegram chat
pub async fn send_document(
&self,
chat_id: &str,
thread_id: Option<&str>,View on GitHub (pinned to 88bb9c8533)
Solutions
- Check the printed target: if it still starts with /workspace/, the remap never happened — configure the channel's workspace_dir to the host directory mounted at the container's /workspace.
- Add the matching volume mount (e.g. -v ./workspace:/workspace) so both sides see the same files.
- Verify with `ls` that the file exists at that exact host path and that the producer finished writing before the send fires.
- Have artifact generators emit absolute paths rooted in the shared workspace.
Example fix
# before — container writes /workspace/out.png, host sender has no workspace_dir # send fails: Telegram attachment path not found: /workspace/out.png # after — share the directory and configure the remap docker run -v "$PWD/workspace:/workspace" ... # and set the telegram channel's workspace_dir to "$PWD/workspace"
Defensive patterns
Strategy: validation
Validate before calling
// resolve the same way the channel does, then verify before sending
let target = if let Some(rel) = raw.strip_prefix("/workspace/") {
workspace_dir.join(rel).to_string_lossy().into_owned()
} else {
raw.to_string()
};
anyhow::ensure!(std::path::Path::new(&target).exists(), "attachment missing before send: {target}"); Type guard
fn attachment_resolves(raw: &str, workspace_dir: Option<&Path>) -> bool {
let p = match raw.strip_prefix("/workspace/") {
Some(rel) => match workspace_dir { Some(ws) => ws.join(rel), None => return false },
None => PathBuf::from(raw),
};
p.exists()
} Try / catch
if let Err(e) = channel.send_attachment(chat, &attachment).await {
if e.to_string().contains("attachment path not found") {
tracing::warn!("artifact vanished; notifying user");
return channel.send_text_chunks("attachment unavailable", chat, thread).await;
}
return Err(e);
} Prevention
- Mount the container workspace into the host (-v $PWD/workspace:/workspace) and set the channel's workspace_dir to the same host path.
- Generate artifacts inside the shared workspace only, with absolute paths.
- Wait for artifact writers to finish (flush/rename on write) before triggering the send.
When it happens
Trigger: Containerized runtime wrote /workspace/artifact.png but workspace_dir is None on the host-side sender, so the /workspace/... path is kept and does not exist on the host; the artifact was deleted (or not yet flushed) between generation and send; workspace_dir points at a different directory than the container volume; relative paths resolved against the sender's cwd.
Common situations: Docker deployment missing the volume mount or the workspace_dir setting; artifacts written to a temp dir that a cleaner reaps before the async send runs; host/container layout drift after moving the workspace.
Related errors
- attachment path {} canonicalizes to {} which escapes workspa
- attachment path {} escapes workspace {}
- attachment path not found: {}
- Docker runtime requires an absolute workspace path, got: {}
- git channel: reading private_key_path `{path}` failed: {e}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/dcceb18a348fc3a3.
Report an issue: GitHub.