can1357/oh-my-pi · warning

mouse x and y must be numbers

Error message

mouse x and y must be numbers

What it means

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.

Source

Thrown at packages/tui/src/debug-server.ts:368

				};
			}
			case "keys": {
				if (typeof request.keys !== "string") throw new Error("keys must be a string");
				const parsed = parseKeyTokens(request.keys);
				for (const sequence of parsed.sequences) this.#tui.injectDebugInput(sequence);
				return { ok: true, injected: parsed.events };
			}
			case "bytes":
				if (typeof request.data !== "string") throw new Error("data must be a string");
				this.#tui.injectDebugInput(request.data);
				return { ok: true };
			case "paste":
				if (typeof request.text !== "string") throw new Error("text must be a string");
				this.#tui.injectDebugInput(`\x1b[200~${request.text}\x1b[201~`);
				return { ok: true };
			case "mouse": {
				if (typeof request.x !== "number" || typeof request.y !== "number")
					throw new Error("mouse x and y must be numbers");
				const action = request.action === undefined ? "click" : request.action;
				if (typeof action !== "string") throw new Error("mouse action must be a string");
				this.#tui.injectDebugInput(mouseSequence(request.x, request.y, action));
				return { ok: true };
			}
			case "quit":
				return { ok: true };
			default:
				return { ok: false, error: `unknown op ${request.op}` };
		}
	}

	#node(component: Component): TuiDebugTreeNode {
		const children = componentChildren(component);
		const focusable = isFocusable(component);
		return {
			kind: componentKind(component),
			...(component.debugId === undefined ? {} : { id: component.debugId }),

View on GitHub (pinned to 9690622007)

Solutions

  1. Include both 'x' and 'y' as JSON numbers in the mouse request payload.
  2. Coerce string coordinates to numbers on the client side before sending (Number(x), parseInt).
  3. Check the client is sending the correct field names ('x' and 'y', not 'col'/'row' or 'left'/'top').
  4. If scripting, wrap the request in try/catch and log the full request object to see which field was wrong.

Example fix

// before
await send({ method: "mouse", x: "120", y: 40 });
// after
await send({ method: "mouse", x: Number(x), y: Number(y) });
Defensive patterns

Strategy: validation

Validate before calling

if (typeof req.x === "number" && typeof req.y === "number" && Number.isFinite(req.x) && Number.isFinite(req.y)) {
  await send({ method: "mouse", x: req.x, y: req.y });
}

Type guard

function hasNumericPoint(v: unknown): v is { x: number; y: number } {
  return typeof v === "object" && v !== null && typeof (v as any).x === "number" && typeof (v as any).y === "number";
}

Try / catch

try {
  await send({ method: "mouse", x, y });
} catch (err) {
  if (err instanceof Error && err.message === "mouse x and y must be numbers") {
    console.error(`mouse request rejected: x=${JSON.stringify(x)} y=${JSON.stringify(y)}`);
  } else throw err;
}

Prevention

When it happens

Trigger: 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}.

Common situations: 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.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/4c59d58ec0489246. Report an issue: GitHub.