{"record":{"id":"4c59d58ec0489246","repo":"can1357/oh-my-pi","slug":"mouse-x-and-y-must-be-numbers","errorCode":null,"errorMessage":"mouse x and y must be numbers","messagePattern":"mouse x and y must be numbers","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/tui/src/debug-server.ts","lineNumber":368,"sourceCode":"\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"keys\": {\n\t\t\t\tif (typeof request.keys !== \"string\") throw new Error(\"keys must be a string\");\n\t\t\t\tconst parsed = parseKeyTokens(request.keys);\n\t\t\t\tfor (const sequence of parsed.sequences) this.#tui.injectDebugInput(sequence);\n\t\t\t\treturn { ok: true, injected: parsed.events };\n\t\t\t}\n\t\t\tcase \"bytes\":\n\t\t\t\tif (typeof request.data !== \"string\") throw new Error(\"data must be a string\");\n\t\t\t\tthis.#tui.injectDebugInput(request.data);\n\t\t\t\treturn { ok: true };\n\t\t\tcase \"paste\":\n\t\t\t\tif (typeof request.text !== \"string\") throw new Error(\"text must be a string\");\n\t\t\t\tthis.#tui.injectDebugInput(`\\x1b[200~${request.text}\\x1b[201~`);\n\t\t\t\treturn { ok: true };\n\t\t\tcase \"mouse\": {\n\t\t\t\tif (typeof request.x !== \"number\" || typeof request.y !== \"number\")\n\t\t\t\t\tthrow new Error(\"mouse x and y must be numbers\");\n\t\t\t\tconst action = request.action === undefined ? \"click\" : request.action;\n\t\t\t\tif (typeof action !== \"string\") throw new Error(\"mouse action must be a string\");\n\t\t\t\tthis.#tui.injectDebugInput(mouseSequence(request.x, request.y, action));\n\t\t\t\treturn { ok: true };\n\t\t\t}\n\t\t\tcase \"quit\":\n\t\t\t\treturn { ok: true };\n\t\t\tdefault:\n\t\t\t\treturn { ok: false, error: `unknown op ${request.op}` };\n\t\t}\n\t}\n\n\t#node(component: Component): TuiDebugTreeNode {\n\t\tconst children = componentChildren(component);\n\t\tconst focusable = isFocusable(component);\n\t\treturn {\n\t\t\tkind: componentKind(component),\n\t\t\t...(component.debugId === undefined ? {} : { id: component.debugId }),","sourceCodeStart":350,"sourceCodeEnd":386,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/tui/src/debug-server.ts#L350-L386","documentation":"The TUI debug server's '#dispatch' handler validates the 'mouse' command's parameters before injecting a synthesized mouse event into the terminal UI. When 'request.x' or 'request.y' are missing or are not JSON numbers, it throws this error instead of building a mouse escape sequence. It is a strict input-contract error: the debug protocol requires numeric coordinates.","triggerScenarios":"Sending a JSON-RPC/debug request with method 'mouse' where 'x' or 'y' is absent, null, a string (e.g. \"100\"), boolean, or NaN-producing value instead of a number. E.g. {\"method\":\"mouse\"} or {\"method\":\"mouse\",\"x\":\"120\",\"y\":40}.","commonSituations":"Hand-writing debug requests against the TUI debug socket; scripting tools that JSON-encode coordinates as strings; a client sending only one coordinate; an older client using a different field name (e.g. 'col'/'row') so both 'x' and 'y' arrive undefined.","solutions":["Include both 'x' and 'y' as JSON numbers in the mouse request payload.","Coerce string coordinates to numbers on the client side before sending (Number(x), parseInt).","Check the client is sending the correct field names ('x' and 'y', not 'col'/'row' or 'left'/'top').","If scripting, wrap the request in try/catch and log the full request object to see which field was wrong."],"exampleFix":"// before\nawait send({ method: \"mouse\", x: \"120\", y: 40 });\n// after\nawait send({ method: \"mouse\", x: Number(x), y: Number(y) });","handlingStrategy":"validation","validationCode":"if (typeof req.x === \"number\" && typeof req.y === \"number\" && Number.isFinite(req.x) && Number.isFinite(req.y)) {\n  await send({ method: \"mouse\", x: req.x, y: req.y });\n}","typeGuard":"function hasNumericPoint(v: unknown): v is { x: number; y: number } {\n  return typeof v === \"object\" && v !== null && typeof (v as any).x === \"number\" && typeof (v as any).y === \"number\";\n}","tryCatchPattern":"try {\n  await send({ method: \"mouse\", x, y });\n} catch (err) {\n  if (err instanceof Error && err.message === \"mouse x and y must be numbers\") {\n    console.error(`mouse request rejected: x=${JSON.stringify(x)} y=${JSON.stringify(y)}`);\n  } else throw err;\n}","preventionTips":["Always send x/y as JSON numbers, never strings.","Coerce user/script input with Number() before building the request.","Use a typed client helper whose signature is (x: number, y: number, action?: string)."],"tags":["validation","debug-protocol","input-validation"],"backgroundTag":"invalid-parameter-type","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}