zeroclaw-labs/zeroclaw · error · anyhow::Error
Slack outbound attachment target must be a local workspace p
Error message
Slack outbound attachment target must be a local workspace path
What it means
Raised by SlackChannel::resolve_outbound_attachment_marker when the target of a parsed outbound attachment marker ([image:...] or [file:...] in outgoing message text) starts with 'file:', 'data:', or contains '://'. This is a deliberate security guard: Slack outbound attachments must reference local workspace files, never URLs or inline data, because the channel uploads the file bytes itself after canonicalizing them inside workspace_dir.
Source
Thrown at crates/zeroclaw-channels/src/slack.rs:1031
Ok(())
}
fn http_client(&self) -> reqwest::Client {
zeroclaw_config::schema::build_channel_proxy_client_with_timeouts(
"channel.slack",
self.proxy_url.as_deref(),
30,
10,
)
}
async fn resolve_outbound_attachment_marker(
&self,
marker: &SlackOutboundAttachmentMarker,
) -> anyhow::Result<MediaAttachment> {
let target = marker.target.trim();
if target.starts_with("file:") || target.starts_with("data:") || target.contains("://") {
anyhow::bail!("Slack outbound attachment target must be a local workspace path");
}
let path = Path::new(target);
if !path.is_absolute() {
anyhow::bail!("Slack outbound attachment path must be absolute: {target}");
}
let workspace = self
.workspace_dir
.as_deref()
.context("Slack outbound local attachments require workspace_dir")?;
let canonical_workspace = tokio::fs::canonicalize(workspace).await.with_context(|| {
format!(
"failed to canonicalize Slack workspace {}",
workspace.display()
)
})?;
let canonical_path = tokio::fs::canonicalize(path)View on GitHub (pinned to 88bb9c8533)
Solutions
- Change the marker target to an absolute local workspace path and let Slack upload the bytes
- If the content only exists remotely, download it into the workspace first, then reference the local path
- Strip or rewrite malformed markers before sending if no upload is intended
Example fix
// before — marker points at a remote URL
let msg = "report ready [image:https://cdn.example.com/chart.png]";
// after — download once, reference the local workspace file
let path = workspace_dir.join("attachments/chart.png"); // populated beforehand
let msg = format!("report ready [image:{}]", path.display()); Defensive patterns
Strategy: validation
Validate before calling
fn sanitize_attachment_markers(msg: &str, workspace_dir: &Path) -> String {
// rewrite [image:<url>] / [file:<url>] markers into local workspace paths,
// dropping markers whose content cannot be downloaded
rewrite_markers(msg, |kind, target| {
if is_local_workspace_target(target) {
Some(format!("[{kind}:{target}]"))
} else {
download_to_workspace(target, workspace_dir)
.ok()
.map(|p| format!("[{kind}:{}]", p.display()))
}
})
} Type guard
fn is_local_workspace_target(target: &str) -> bool {
!(target.starts_with("file:") || target.starts_with("data:") || target.contains("://"))
} Prevention
- Validate marker targets with the same rule the channel uses (no file:, data:, or ://) before sending
- Download remote assets into workspace_dir first and reference the local absolute path
- When emitting markers from templates, only ever interpolate workspace-absolute paths
When it happens
Trigger: Outgoing message text contains a marker like [image:https://cdn.example.com/pic.png] or [file:data:text/plain;base64,...]; parse_outbound_attachment_markers extracts it and resolve_outbound_attachment_marker rejects the target scheme before any path work.
Common situations: An agent or template emits remote URLs or data URIs in attachment markers, expecting them to be forwarded as-is; porting behavior from another channel that accepted URLs; markdown link syntax colliding with the marker grammar.
Related errors
- Slack outbound attachment path must be absolute: {target}
- Slack outbound attachment path escapes workspace: {}
- Slack outbound attachment target is not a file: {}
- 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/c2d2a4c1a88b33db.
Report an issue: GitHub.