{"record":{"id":"89dd40c418981282","repo":"zeroclaw-labs/zeroclaw","slug":"lark-feishu-marker-target-is-empty","errorCode":null,"errorMessage":"Lark/Feishu marker target is empty","messagePattern":"Lark/Feishu marker target is empty","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/lark.rs","lineNumber":575,"sourceCode":"}\n\nfn lark_outgoing_media_from_marker(\n    kind: String,\n    target: String,\n) -> Option<LarkOutgoingMediaMarker> {\n    Some(LarkOutgoingMediaMarker {\n        kind: LarkOutgoingMediaKind::from_marker_kind(&kind)?,\n        target,\n    })\n}\n\nfn validate_lark_marker_target(\n    target: &str,\n    workspace_dir: Option<&Path>,\n) -> anyhow::Result<PathBuf> {\n    let trimmed = target.trim();\n    if trimmed.is_empty() {\n        anyhow::bail!(\"Lark/Feishu marker target is empty\");\n    }\n\n    let lower = trimmed.to_ascii_lowercase();\n    if lower.starts_with(\"http://\")\n        || lower.starts_with(\"https://\")\n        || lower.starts_with(\"data:\")\n        || lower.starts_with(\"file:\")\n        || lower.contains(\"://\")\n    {\n        ::zeroclaw_log::record!(\n            WARN,\n            ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note)\n                .with_attrs(::serde_json::json!({\"reason\": \"disallowed_scheme\"})),\n            \"lark: marker target uses disallowed scheme\"\n        );\n        anyhow::bail!(\"Lark/Feishu marker target uses a disallowed scheme\");\n    }\n","sourceCodeStart":557,"sourceCodeEnd":593,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/lark.rs#L557-L593","documentation":"validate_lark_marker_target is the first stop when turning an outgoing media marker (image/file kind like image, document, video, voice) into an uploadable local path; it rejects a target that trims to empty before any scheme or workspace checks. The marker target is supposed to be a workspace-relative (or absolute) file path, so an empty string means the agent/tool that produced the marker emitted no path at all.","triggerScenarios":"The model emits a media marker (e.g. an image attachment directive) whose target field is \"\" or only whitespace; resolve_lark_media_marker (called from send/finalize_draft) routes it into validate_lark_marker_target and the empty-trim guard fires.","commonSituations":"Agent prompt/template for Lark media output has an empty placeholder; a tool that generates files failed but still emitted a marker; JSON marker parsing lost the path field (key typo like 'path' vs 'target').","solutions":["Fix the marker producer (agent tool or prompt) so the target is always the non-empty path of the generated file","Validate marker payloads at the boundary where the model's structured output is parsed — drop or retry markers with a blank target before they reach the channel","If a file-generation tool failed upstream, make its failure visible instead of letting an empty marker flow into send"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Validate markers at parse time, before they reach the channel:\nfn valid_marker(kind: &str, target: &str) -> bool {\n    matches!(kind.to_ascii_lowercase().as_str(), \"image\"|\"photo\"|\"document\"|\"file\"|\"video\"|\"audio\"|\"voice\")\n        && !target.trim().is_empty()\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = channel.send(&msg).await {\n    if e.to_string().contains(\"marker target is empty\") {\n        // drop or regenerate the marker upstream; do not retry the same message\n    }\n}","preventionTips":["Validate structured agent output (marker kind + target) at the parse boundary","Make file-producing tools return the written path and inject it into markers, instead of letting the model type one"],"tags":["lark","media-marker","validation","upload"],"backgroundTag":"empty-required-field","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}