{"record":{"id":"e1e7d25550b05ab1","repo":"can1357/oh-my-pi","slug":"multiple-windows-match-json-stringify-selector","errorCode":null,"errorMessage":"multiple windows match ${JSON.stringify(selector)}:\\n${candidates}","messagePattern":"multiple windows match (.+?):\\\\n(.+?)","errorType":"exception","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/computer/worker.ts","lineNumber":685,"sourceCode":"\t\t\twindows: async (filter?: WindowFilter): Promise<DesktopWindow[]> => {\n\t\t\t\tconst { signal } = getContext();\n\t\t\t\treturn (await nativeCall(signal, () => session.listWindows())).filter(window =>\n\t\t\t\t\tmatchesFilter(window, filter),\n\t\t\t\t);\n\t\t\t},\n\t\t\twindow: async (selector: string | WindowFilter): Promise<Win> => {\n\t\t\t\tconst { signal } = getContext();\n\t\t\t\tconst windows = await nativeCall(signal, () => session.listWindows());\n\t\t\t\tconst matches =\n\t\t\t\t\ttypeof selector === \"string\"\n\t\t\t\t\t\t? windows.filter(window => window.id === selector)\n\t\t\t\t\t\t: windows.filter(window => matchesFilter(window, selector));\n\t\t\t\tif (matches.length === 0) throw new ToolError(`no window matches ${JSON.stringify(selector)}`);\n\t\t\t\tif (matches.length > 1) {\n\t\t\t\t\tconst candidates = matches\n\t\t\t\t\t\t.map(window => `${window.id} ${window.app} ${JSON.stringify(window.title)}`)\n\t\t\t\t\t\t.join(\"\\n\");\n\t\t\t\t\tthrow new ToolError(`multiple windows match ${JSON.stringify(selector)}:\\n${candidates}`);\n\t\t\t\t}\n\t\t\t\treturn makeWin(matches[0]!);\n\t\t\t},\n\t\t\tfocusedWindow: async (): Promise<Win | null> => {\n\t\t\t\tconst { signal } = getContext();\n\t\t\t\tconst window = (await nativeCall(signal, () => session.listWindows())).find(candidate => candidate.focused);\n\t\t\t\treturn window ? makeWin(window) : null;\n\t\t\t},\n\t\t\tscreenshot: (options?: ScreenshotOptions) => captureScreenshot(session, getContext, \"desktop\", options),\n\t\t\tclick: desktopTarget.click.bind(desktopTarget),\n\t\t\tdoubleClick: desktopTarget.doubleClick.bind(desktopTarget),\n\t\t\tmove: desktopTarget.move.bind(desktopTarget),\n\t\t\tdrag: desktopTarget.drag.bind(desktopTarget),\n\t\t\tscroll: desktopTarget.scroll.bind(desktopTarget),\n\t\t\ttype: desktopTarget.type.bind(desktopTarget),\n\t\t\tpress: desktopTarget.press.bind(desktopTarget),\n\t\t\telementAt: async (x: number, y: number): Promise<El | null> => {\n\t\t\t\tconst { signal } = getContext();","sourceCodeStart":667,"sourceCodeEnd":703,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/computer/worker.ts#L667-L703","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Narrow the selector: add the exact window title or use the specific window id from the candidate list printed in the error.","Call desktop.windows(filter) to enumerate matches and pick one programmatically (e.g. the focused one or by title substring).","Add more filter criteria (app plus title) until exactly one window matches.","If operating on any matching window is fine, take matches[0] from windows() instead of using window()."],"exampleFix":"// before\nconst win = await desktop.window({app: 'Chrome'});\n// after\nconst chromeWins = await desktop.windows({app: 'Chrome'});\nconst win = await desktop.window(chromeWins.find(w => w.title.includes('Docs'))!.id);","handlingStrategy":"validation","validationCode":"const matches = await desktop.windows(selector);\nif (matches.length > 1) throw new Error(`ambiguous: ${matches.length} windows match`);\nif (matches.length === 0) throw new Error('no match');\nconst win = await desktop.window(matches[0].id);","typeGuard":null,"tryCatchPattern":"try {\n  const win = await desktop.window(selector);\n} catch (err) {\n  if (String(err?.message).startsWith('multiple windows match')) {\n    const matches = await desktop.windows(selector);\n    const win = await desktop.window(matches[0].id); // or pick by title\n  } else throw err;\n}","preventionTips":["Filter by unique window id, not app or partial title.","Combine app + exact title filters to guarantee uniqueness.","Enumerate with windows() first and assert length === 1.","Avoid selectors that are valid on single-window dev machines but ambiguous in real sessions."],"tags":["computer-tool","window-selector","ambiguity","automation"],"backgroundTag":"ambiguous-selector-match","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}