{"record":{"id":"b19669a87b404ab1","repo":"can1357/oh-my-pi","slug":"mouse-action-must-be-a-string","errorCode":null,"errorMessage":"mouse action must be a string","messagePattern":"mouse action must be a string","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/tui/src/debug-server.ts","lineNumber":370,"sourceCode":"\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 }),\n\t\t\t...(focusable ? { focusable: true, focused: component === this.#tui.getFocused() } : {}),\n\t\t\t...(children.length === 0 ? {} : { children: children.map(child => this.#node(child)) }),","sourceCodeStart":352,"sourceCodeEnd":388,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/tui/src/debug-server.ts#L352-L388","documentation":"In the debug server's 'mouse' command handler, 'request.action' defaults to 'click' when undefined, but if it is present and not a string, this error is thrown before any mouse sequence is injected. The debug protocol only accepts known string actions (e.g. click, move, drag).","triggerScenarios":"Sending a debug 'mouse' request where 'action' is a number, boolean, null, or an object — e.g. {\"method\":\"mouse\",\"x\":10,\"y\":20,\"action\":1} or \"action\":null. Note explicit null is NOT treated as undefined, so it fails.","commonSituations":"Clients that serialize the action field from an enum as a number; passing a null from a JS client (null !== undefined); typos producing undefined is fine but a mistyped variable holding a non-string slips through.","solutions":["Send 'action' as a string (or omit it entirely to get the 'click' default).","Map numeric enum actions to their string names on the client before sending.","Ensure the action is a valid action name accepted by mouseSequence (e.g. \"click\").","Remove the 'action': null field explicitly rather than sending null."],"exampleFix":"// before\nawait send({ method: \"mouse\", x: 10, y: 20, action: MouseButton.Left }); // number\n// after\nawait send({ method: \"mouse\", x: 10, y: 20, action: \"click\" }); // or omit action","handlingStrategy":"validation","validationCode":"const ACTIONS = new Set([\"click\", \"move\", \"drag\"]);\nif (typeof action === \"string\" && ACTIONS.has(action)) {\n  await send({ method: \"mouse\", x, y, action });\n} // or omit action to default to \"click\"","typeGuard":"function isMouseAction(v: unknown): v is string {\n  return typeof v === \"string\";\n}","tryCatchPattern":"try {\n  await send({ method: \"mouse\", x, y, action });\n} catch (err) {\n  if (err instanceof Error && err.message === \"mouse action must be a string\") {\n    console.error(`invalid mouse action: ${JSON.stringify(action)}`);\n  } else throw err;\n}","preventionTips":["Omit the action field to use the 'click' default instead of passing null/undefined-like values.","Keep action as a string enum on the client; serialize enum members to their string names.","Never send null for optional fields — delete the key instead."],"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"}