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

  1. 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.
  2. Add the matching volume mount (e.g. -v ./workspace:/workspace) so both sides see the same files.
  3. Verify with `ls` that the file exists at that exact host path and that the producer finished writing before the send fires.
  4. 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

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


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/dcceb18a348fc3a3. Report an issue: GitHub.