zeroclaw-labs/zeroclaw · error · anyhow::Error
Slack outbound attachment target is not a file: {}
Error message
Slack outbound attachment target is not a file: {} What it means
Raised by SlackChannel::resolve_outbound_attachment_marker when tokio::fs::metadata succeeds on the canonicalized target but metadata.is_file() is false — the target is a directory, fifo, device node, or other non-regular file. It fires after the workspace containment check and before the size check against SLACK_OUTBOUND_ATTACHMENT_MAX_BYTES (20 MiB), so the marker target must be a readable regular file inside the workspace.
Source
Thrown at crates/zeroclaw-channels/src/slack.rs:1069
.with_context(|| format!("Slack outbound attachment path not found: {target}"))?;
if !canonical_path.starts_with(&canonical_workspace) {
anyhow::bail!(
"Slack outbound attachment path escapes workspace: {}",
canonical_path.display()
);
}
let metadata = tokio::fs::metadata(&canonical_path)
.await
.with_context(|| {
format!(
"failed to stat Slack outbound attachment {}",
canonical_path.display()
)
})?;
if !metadata.is_file() {
anyhow::bail!(
"Slack outbound attachment target is not a file: {}",
canonical_path.display()
);
}
if metadata.len() > SLACK_OUTBOUND_ATTACHMENT_MAX_BYTES as u64 {
anyhow::bail!(
"Slack outbound attachment exceeds {} bytes: {}",
SLACK_OUTBOUND_ATTACHMENT_MAX_BYTES,
canonical_path.display()
);
}
let data = tokio::fs::read(&canonical_path).await.with_context(|| {
format!(
"failed to read Slack outbound attachment {}",
canonical_path.display()
)
})?;View on GitHub (pinned to 88bb9c8533)
Solutions
- Point the marker at a specific regular file inside the workspace
- If the intent was 'attach everything in this directory', enumerate the files and emit one marker per file
- Generate the asset fully (close/flush writers) before the marker is resolved
Defensive patterns
Strategy: validation
Validate before calling
async fn attachment_is_sendable(target: &str) -> bool {
match tokio::fs::metadata(target).await {
Ok(m) => m.is_file() && m.len() <= 20 * 1024 * 1024, // regular file, <= SLACK_OUTBOUND_ATTACHMENT_MAX_BYTES
Err(_) => false,
}
} Prevention
- Stat the target before sending: must be a regular file, not a directory or special file
- Point markers at concrete generated files, never at output directories
- Also check the 20 MiB size cap up front — the adjacent guard rejects oversized files after this one
When it happens
Trigger: An outbound attachment marker points at a directory (e.g. [file:/workspace/reports]) or a special file; the stat succeeds, is_file() is false, and the bail includes the canonical path.
Common situations: Agents referencing a folder of exports instead of a specific file; markers generated from a path where the file was expected but a directory was created; trailing-slash or empty-name paths resolving to a directory.
Related errors
- Slack outbound attachment target must be a local workspace p
- Slack outbound attachment path must be absolute: {target}
- Slack outbound attachment path escapes workspace: {}
- attachment path not found: {}
- inbound attachment exceeds {} MB limit
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/4a50e956177092d2.
Report an issue: GitHub.