can1357/oh-my-pi · error · ToolError
${XD_URL_PREFIX}${device.name} expects a JSON args object as
Error message
${XD_URL_PREFIX}${device.name} expects a JSON args object as content (${error instanceof Error ? error.message : String(error)}). Write `?` for docs. What it means
xd:// devices take their arguments as a JSON object carried in the write `content`. parseDeviceArgs runs JSON.parse on the content, and if it is not valid JSON it throws this ToolError naming the device, the JSON parse error, and a hint to write `?` as content to fetch the device's docs.
Source
Thrown at packages/coding-agent/src/tools/xdev.ts:159
}
/**
* Parse and validate a device write's JSON `content` against the wrapped
* tool's wire schema. Strips a habitual top-level `i` (intent) unless the
* schema declares one. Throws ToolError; schema-mismatch errors carry `docs()`
* for repair.
*/
function parseDeviceArgs(
device: AiTool,
content: string,
toolCallId: string,
docs: () => string,
): Record<string, unknown> {
let parsed: unknown;
try {
parsed = JSON.parse(content);
} catch (error) {
throw new ToolError(
`${XD_URL_PREFIX}${device.name} expects a JSON args object as content (${error instanceof Error ? error.message : String(error)}). Write \`?\` for docs.`,
);
}
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
throw new ToolError(
`${XD_URL_PREFIX}${device.name} content must be a JSON object, got ${Array.isArray(parsed) ? "array" : typeof parsed}.`,
);
}
// The harness only injects the intent field into top-level schemas; strip a
// habitual `i` from inner args unless the wrapped schema really declares it.
const args: Record<string, unknown> = { ...(parsed as Record<string, unknown>) };
if ("i" in args && !schemaDeclaresIntentField(toolWireSchema(device))) delete args.i;
try {
return validateToolArguments(device, {
type: "toolCall",
id: toolCallId,
name: device.name,
arguments: args,View on GitHub (pinned to 9690622007)
Solutions
- Send the arguments as a valid JSON object, e.g. {"key": "value"}.
- Write `?` as content to `xd://<device>` to retrieve the device's docs and schema.
- Validate the content with JSON.parse (or a linter) before the write.
- Remove non-JSON decoration: no comments, trailing commas, single quotes, or surrounding prose.
Example fix
// before
write({ path: "xd://browser", content: "navigate to example.com" })
// after
write({ path: "xd://browser", content: "{\"action\":\"navigate\",\"url\":\"https://example.com\"}" }) Defensive patterns
Strategy: validation
Validate before calling
try { JSON.parse(content); } catch (err) { throw new Error(`xd:// content must be valid JSON: ${err.message}`); } Type guard
function isJsonString(s: string): boolean { try { JSON.parse(s); return true; } catch { return false; } } Try / catch
try { await write({ path: `xd://${device}`, content }); } catch (e) { if (String(e.message).includes("expects a JSON args object")) { const docs = await write({ path: `xd://${device}`, content: "?" }); /* rebuild JSON args from docs */ } else throw e; } Prevention
- Always JSON.stringify the args object before writing to xd:// devices.
- Write `?` as content first to learn the device's schema.
- Strip comments/trailing commas that break strict JSON.parse.
- Avoid free-text prose in xd:// content.
When it happens
Trigger: Calling Write to `xd://<device>` with content that is not parseable JSON — e.g. plain prose, a shell-style flag string, trailing commas, single quotes, or markdown wrapping the JSON.
Common situations: An agent writes natural-language instructions or key=value text to an xd:// device instead of a JSON object; or the JSON got mangled by escaping/quoting issues.
Related errors
- ${XD_URL_PREFIX}${device.name} content must be a JSON object
- Cannot write to xd:// itself — pick a device:\n${xdevListing
- Invalid args for ${XD_URL_PREFIX}${device.name}: ${message}\
- No such tool: ${XD_URL_PREFIX}${name}. Mounted devices: ${[.
- Replacement text is not valid UTF-8: {err}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/5bd602d6e309148f.
Report an issue: GitHub.