zeroclaw-labs/zeroclaw · error · anyhow::Error

Lark/Feishu marker target is not a file

Error message

Lark/Feishu marker target is not a file

What it means

resolve_lark_media_marker stats the validated path and requires metadata.is_file() — the marker target must resolve to a regular file, not a directory, fifo, socket or device. All scheme/workspace containment checks already passed by this point, so this error specifically means: the path exists, is inside the workspace, but is not something uploadable as image/file content.

Source

Thrown at crates/zeroclaw-channels/src/lark.rs:656

        );
        anyhow::bail!("Lark/Feishu marker target resolves outside workspace_dir");
    }

    Ok(candidate)
}

fn resolve_lark_media_marker(
    marker: &LarkOutgoingMediaMarker,
    workspace_dir: Option<&Path>,
) -> anyhow::Result<LarkResolvedMediaMarker> {
    let path = validate_lark_marker_target(&marker.target, workspace_dir)?;
    let metadata = std::fs::metadata(&path).map_err(|err| {
        anyhow::Error::msg(format!(
            "read Lark/Feishu marker target metadata failed: {err}"
        ))
    })?;
    if !metadata.is_file() {
        anyhow::bail!("Lark/Feishu marker target is not a file");
    }
    if metadata.len() == 0 {
        anyhow::bail!("Lark/Feishu marker target is empty");
    }
    let file_name = path
        .file_name()
        .and_then(|name| name.to_str())
        .unwrap_or("attachment")
        .to_string();

    Ok(LarkResolvedMediaMarker {
        kind: marker.kind,
        path,
        file_name,
    })
}

async fn build_lark_image_upload_form(marker: &LarkResolvedMediaMarker) -> anyhow::Result<Form> {

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Point the marker at the concrete file including its filename ("screenshots/run-42.png", not "screenshots/")
  2. Have the file-producing tool return the exact artifact path it wrote and feed that verbatim into the marker
  3. If attaching multiple files, emit one marker per file rather than one marker per directory

Example fix

// before
{ "kind": "image", "target": "reports/daily" }   // a directory

// after
{ "kind": "image", "target": "reports/daily/chart.png" }
Defensive patterns

Strategy: validation

Validate before calling

// Before sending, confirm the marker resolves to a regular file:
let p = std::fs::canonicalize(workspace.join(target.trim()))?;
anyhow::ensure!(std::fs::metadata(&p)?.is_file(), "marker target is not a regular file: {p:?}");

Try / catch

if let Err(e) = channel.send(&msg).await {
    if e.to_string().contains("is not a file") {
        // append the concrete filename to the target and retry
    }
}

Prevention

When it happens

Trigger: A marker points at a directory ("screenshots/" or "attachments" without a filename) or at a special file; std::fs::metadata succeeds, is_file() is false, and send/finalize_draft bail before reading bytes or building the upload form.

Common situations: Agent truncates a path to its folder; tool writes to a directory and passes the folder as the artifact; marker built by joining a base dir while the filename component was empty.

Related errors


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