zeroclaw-labs/zeroclaw · error · anyhow::Error
Screenshot 'path' parameter must be a string, got { $path }
Error message
Screenshot 'path' parameter must be a string, got { $path } What it means
In the computer-use flow, the screenshot `path` argument is classified as Absent, String, or NonString. Null, missing, or empty-string means 'return the PNG inline'; a string is validated as a write target; every other JSON type (integer, array, object, boolean) hits the NonString arm and is rejected with the debug-formatted value. The strictness exists because the validated value is later used for a local filesystem write.
Source
Thrown at crates/zeroclaw-tools/src/browser.rs:1030
// String: validate against workspace through the one canonical
// validator shared with the local backends.
let mut args = args;
let resolved_target = self.validate_screenshot_target(path_str).await?;
// Store the validated path for local write after sidecar returns PNG.
// Do NOT forward the path to the sidecar - it returns PNG bytes.
if let Some(obj) = args.as_object_mut() {
obj.insert("path".to_string(), Value::String(resolved_target));
}
Ok(args)
}
Some(_) => {
// NonString: integer, array, object → reject
let msg = crate::i18n::get_required_tool_string_with_args(
"tool-browser-screenshot-error-computeruse-non-string-path",
&[("path", &format!("{path:?}"))],
);
anyhow::bail!("{msg}");
}
}
}
async fn execute_computer_use_action(
&self,
action: &str,
args: &Value,
) -> anyhow::Result<ToolResult> {
let endpoint = self.computer_use_endpoint_url()?;
// Validate screenshot path but do NOT forward it to the sidecar.
// The sidecar returns PNG bytes, and we perform the validated local write.
let validated_path = if action == "screenshot" {
match self
.validate_screenshot_path_for_computer_use(action, args.clone())
.await
{View on GitHub (pinned to 88bb9c8533)
Solutions
- Pass path as a JSON string ("screenshots/shot.png") or omit it entirely to get the PNG inline
- Enforce the tool's parameters schema (type: string) before dispatch
- Treat empty string as 'inline PNG' if no file write is wanted
Example fix
// before
{"action": "screenshot", "path": 1}
// after
{"action": "screenshot", "path": "screenshots/shot.png"} Defensive patterns
Strategy: type-guard
Validate before calling
if !matches!(args.get("path"), None | Some(serde_json::Value::Null) | Some(serde_json::Value::String(_))) {
return Err("screenshot 'path' must be a string, null, or absent".into());
} Type guard
fn is_valid_screenshot_path_param(args: &serde_json::Value) -> bool {
match args.get("path") {
None | Some(serde_json::Value::Null) => true,
Some(serde_json::Value::String(_)) => true,
_ => false,
}
} Try / catch
match tool.execute(args).await {
Ok(res) if res.success => { /* ... */ }
Ok(res) => { /* res.error carries the rejection; fix the arg type, not the environment */ }
Err(e) => return Err(e),
} Prevention
- Validate tool arguments against parameters_schema before dispatch
- Keep path parameters as plain strings end to end
- Log rejected argument shapes to spot schema drift in callers
When it happens
Trigger: Sending {"action": "screenshot", "path": 0}, {"path": ["shot.png"]}, or {"path": {"file": "shot.png"}} to the browser tool with computer-use configured.
Common situations: An LLM emits a numeric flag or a structured object where a path string was expected; upstream code forwards unvalidated JSON; a model confuses the numeric `pixels` parameter with `path`.
Related errors
- computer-use sidecar returned an empty screenshot payload
- computer-use sidecar returned a non-PNG screenshot payload
- Failed to parse Ollama response: {e}
- AIEOS payload must be a JSON object
- Cannot write screenshot to runtime config path '{ $target }'
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/66aa1169b69d913d.
Report an issue: GitHub.