can1357/oh-my-pi · error · ToolError

multiple windows match ${JSON.stringify(selector)}:\n${candi

Error message

multiple windows match ${JSON.stringify(selector)}:\n${candidates}

What it means

Thrown by the computer tool's desktop.window(selector) API when the selector matches more than one open window. Because a Win handle must refer to exactly one window, the tool refuses to guess and lists every matching candidate (id, app, title) in the message so the caller can disambiguate.

Source

Thrown at packages/coding-agent/src/tools/computer/worker.ts:685

			windows: async (filter?: WindowFilter): Promise<DesktopWindow[]> => {
				const { signal } = getContext();
				return (await nativeCall(signal, () => session.listWindows())).filter(window =>
					matchesFilter(window, filter),
				);
			},
			window: async (selector: string | WindowFilter): Promise<Win> => {
				const { signal } = getContext();
				const windows = await nativeCall(signal, () => session.listWindows());
				const matches =
					typeof selector === "string"
						? windows.filter(window => window.id === selector)
						: windows.filter(window => matchesFilter(window, selector));
				if (matches.length === 0) throw new ToolError(`no window matches ${JSON.stringify(selector)}`);
				if (matches.length > 1) {
					const candidates = matches
						.map(window => `${window.id} ${window.app} ${JSON.stringify(window.title)}`)
						.join("\n");
					throw new ToolError(`multiple windows match ${JSON.stringify(selector)}:\n${candidates}`);
				}
				return makeWin(matches[0]!);
			},
			focusedWindow: async (): Promise<Win | null> => {
				const { signal } = getContext();
				const window = (await nativeCall(signal, () => session.listWindows())).find(candidate => candidate.focused);
				return window ? makeWin(window) : null;
			},
			screenshot: (options?: ScreenshotOptions) => captureScreenshot(session, getContext, "desktop", options),
			click: desktopTarget.click.bind(desktopTarget),
			doubleClick: desktopTarget.doubleClick.bind(desktopTarget),
			move: desktopTarget.move.bind(desktopTarget),
			drag: desktopTarget.drag.bind(desktopTarget),
			scroll: desktopTarget.scroll.bind(desktopTarget),
			type: desktopTarget.type.bind(desktopTarget),
			press: desktopTarget.press.bind(desktopTarget),
			elementAt: async (x: number, y: number): Promise<El | null> => {
				const { signal } = getContext();

View on GitHub (pinned to 9690622007)

Solutions

  1. Narrow the selector: add the exact window title or use the specific window id from the candidate list printed in the error.
  2. Call desktop.windows(filter) to enumerate matches and pick one programmatically (e.g. the focused one or by title substring).
  3. Add more filter criteria (app plus title) until exactly one window matches.
  4. If operating on any matching window is fine, take matches[0] from windows() instead of using window().

Example fix

// before
const win = await desktop.window({app: 'Chrome'});
// after
const chromeWins = await desktop.windows({app: 'Chrome'});
const win = await desktop.window(chromeWins.find(w => w.title.includes('Docs'))!.id);
Defensive patterns

Strategy: validation

Validate before calling

const matches = await desktop.windows(selector);
if (matches.length > 1) throw new Error(`ambiguous: ${matches.length} windows match`);
if (matches.length === 0) throw new Error('no match');
const win = await desktop.window(matches[0].id);

Try / catch

try {
  const win = await desktop.window(selector);
} catch (err) {
  if (String(err?.message).startsWith('multiple windows match')) {
    const matches = await desktop.windows(selector);
    const win = await desktop.window(matches[0].id); // or pick by title
  } else throw err;
}

Prevention

When it happens

Trigger: Calling desktop.window({app: 'Chrome'}) with multiple Chrome windows open; calling desktop.window({title: 'Untitled'}) matching several documents; any filter (or id-less selection) that is not unique across the current window list.

Common situations: Browsers and editors commonly have many windows with similar titles; automation written against a single-window machine breaks on a multi-window desktop; partial title filters that were unique during development match several windows in production.

Related errors


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