{"record":{"id":"23236c634eb814d4","repo":"can1357/oh-my-pi","slug":"xd-url-prefix-device-name-content-must-be-a-j","errorCode":null,"errorMessage":"${XD_URL_PREFIX}${device.name} content must be a JSON object, got ${Array.isArray(parsed) ? \"array\" : typeof parsed}.","messagePattern":"(.+?)(.+?) content must be a JSON object, got (.+?)\\.","errorType":"validation","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/xdev.ts","lineNumber":164,"sourceCode":" * schema declares one. Throws ToolError; schema-mismatch errors carry `docs()`\n * for repair.\n */\nfunction parseDeviceArgs(\n\tdevice: AiTool,\n\tcontent: string,\n\ttoolCallId: string,\n\tdocs: () => string,\n): Record<string, unknown> {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(content);\n\t} catch (error) {\n\t\tthrow new ToolError(\n\t\t\t`${XD_URL_PREFIX}${device.name} expects a JSON args object as content (${error instanceof Error ? error.message : String(error)}). Write \\`?\\` for docs.`,\n\t\t);\n\t}\n\tif (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\tthrow new ToolError(\n\t\t\t`${XD_URL_PREFIX}${device.name} content must be a JSON object, got ${Array.isArray(parsed) ? \"array\" : typeof parsed}.`,\n\t\t);\n\t}\n\t// The harness only injects the intent field into top-level schemas; strip a\n\t// habitual `i` from inner args unless the wrapped schema really declares it.\n\tconst args: Record<string, unknown> = { ...(parsed as Record<string, unknown>) };\n\tif (\"i\" in args && !schemaDeclaresIntentField(toolWireSchema(device))) delete args.i;\n\ttry {\n\t\treturn validateToolArguments(device, {\n\t\t\ttype: \"toolCall\",\n\t\t\tid: toolCallId,\n\t\t\tname: device.name,\n\t\t\targuments: args,\n\t\t});\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new ToolError(`Invalid args for ${XD_URL_PREFIX}${device.name}: ${message}\\n\\n${docs()}`);\n\t}","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/xdev.ts#L146-L182","documentation":"After JSON parsing succeeds, parseDeviceArgs requires the parsed value to be a plain JSON object (null, arrays, and primitives are rejected) because device arguments are keyed by parameter name. It throws this ToolError stating what was received instead (array, null, string, number, etc.).","triggerScenarios":"Writing `[]`, `[1,2]`, `\"text\"`, `42`, `true`, or `null` as content to `xd://<device>` — syntactically valid JSON but not an object.","commonSituations":"An agent sends a JSON array of items when the device schema expects named fields, or sends a bare JSON string/number it believed was already the payload.","solutions":["Wrap the payload in a JSON object with named fields matching the device schema: {\"items\": [...]}.","Write `?` as content to `xd://<device>` to see the expected schema.","Use the device's docs to find the object field that should hold a list, instead of sending a top-level array."],"exampleFix":"// before\nwrite({ path: \"xd://search\", content: \"[\\\"query\\\"]\" })\n// after\nwrite({ path: \"xd://search\", content: \"{\\\"query\\\":\\\"...\\\"}\" })","handlingStrategy":"type-guard","validationCode":"const parsed = JSON.parse(content); if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) throw new Error(\"xd:// args must be a JSON object\");","typeGuard":"function isJsonObject(v: unknown): v is Record<string, unknown> { return typeof v === \"object\" && v !== null && !Array.isArray(v); }","tryCatchPattern":"try { await write({ path, content }); } catch (e) { if (String(e.message).includes(\"must be a JSON object, got\")) { const parsed = JSON.parse(content); await write({ path, content: JSON.stringify({ items: parsed }) }); } else throw e; }","preventionTips":["Wrap list payloads in an object field instead of sending top-level arrays.","Never send bare scalars/strings as device args.","Check the device schema via `?` content before composing args.","Use JSON.stringify on a Record<string, unknown>, never on unknown shapes."],"tags":["json","tool-error","xdev","schema"],"backgroundTag":"invalid-json-args","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}