zeroclaw-labs/zeroclaw · error · anyhow::Error
computer-use sidecar returned an empty screenshot payload
Error message
computer-use sidecar returned an empty screenshot payload
What it means
For a path-bearing computer-use screenshot, ZeroClaw calls the sidecar, decodes data.png_base64, and requires a non-empty decoded buffer before writing locally. The flow is fail-closed: success must mean the file was actually created, so an empty payload aborts with this error instead of reporting success without a file.
Source
Thrown at crates/zeroclaw-tools/src/browser.rs:1167
.as_ref()
.and_then(|d| d.get("png_base64"))
.and_then(|v| v.as_str())
.ok_or_else(|| {
anyhow::Error::msg(crate::i18n::get_required_tool_string(
"tool-browser-screenshot-error-sidecar-no-png-data",
))
})?;
// Decode and validate the PNG payload: it must decode to a
// non-empty buffer with a PNG signature. Base64-decodable
// arbitrary bytes are NOT a valid screenshot — writing them
// to the `.png` destination would turn the sidecar boundary
// into an arbitrary decoded-byte write.
let png_bytes = base64::engine::general_purpose::STANDARD
.decode(png_data)
.with_context(|| "Failed to decode PNG base64 data")?;
if png_bytes.is_empty() {
anyhow::bail!(crate::i18n::get_required_tool_string(
"tool-browser-screenshot-error-sidecar-empty-png",
));
}
const PNG_SIGNATURE: &[u8] =
&[0x89, b'P', b'N', b'G', b'\r', b'\n', 0x1a, b'\n'];
if !png_bytes.starts_with(PNG_SIGNATURE) {
anyhow::bail!(crate::i18n::get_required_tool_string(
"tool-browser-screenshot-error-sidecar-not-png",
));
}
tokio::fs::write(path_str, &png_bytes)
.await
.with_context(|| format!("Failed to write screenshot to {path_str}"))?;
// Return success with the path information
let output = serde_json::to_string_pretty(&json!({
"backend": "computer_use",View on GitHub (pinned to 88bb9c8533)
Solutions
- Check the sidecar's own logs for why the capture produced zero bytes
- Verify the sidecar version and response contract (ComputerUseResponse with data.png_base64) and upgrade the mismatched side
- Retry once — transient capture races can produce empty frames; if it persists, report it as a sidecar bug
Defensive patterns
Strategy: try-catch
Try / catch
match tool.execute(args).await {
Ok(res) if res.success => { /* file written */ }
Ok(res) => {
if res.error.as_deref().unwrap_or_default().contains("empty screenshot payload") {
// sidecar contract violation: retry once, then report to the sidecar owner
}
}
Err(e) => return Err(e),
} Prevention
- Pin and version-check the sidecar contract at startup
- Treat empty/non-PNG payload errors as sidecar bugs, not agent mistakes
- Run a smoke screenshot against the sidecar during deployment
When it happens
Trigger: The sidecar replies 2xx with success=true but png_base64="" (or content that decodes to zero bytes) for a screenshot request that carries a destination path.
Common situations: Sidecar bug or version mismatch returning a canned/empty payload; screen capture failing silently in headless sessions with no visible window; sidecar stubs in tests returning shape-valid but empty responses.
Related errors
- computer-use sidecar returned a non-PNG screenshot payload
- Screenshot 'path' parameter must be a string, got { $path }
- notion.database_id must not be empty when notion.enabled = t
- jira.base_url must not be empty when jira.enabled = true
- Cannot write screenshot to runtime config path '{ $target }'
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/1fbf494cd34ec7aa.
Report an issue: GitHub.