{"record":{"id":"bfeccadfe677148c","repo":"jackwener/OpenCLI","slug":"search-type-failed","errorCode":null,"errorMessage":"search type failed","messagePattern":"search type failed","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/qoder/ui.js","lineNumber":92,"sourceCode":"        const query = String(kwargs?.query || '').trim();\n        if (!query) throw new ArgumentError('query', 'is required');\n        const limit = parsePositiveInt(kwargs?.limit, 20, '--limit');\n        const openRes = await evaluateQoder(page, clickByTextScript(['Search']));\n        if (!openRes?.ok) throw new CommandExecutionError(openRes?.reason || 'search open failed', '');\n        await page.wait(0.5);\n        // Type into the visible input (usually the most-recently mounted one).\n        const fillRes = await evaluateQoder(page, `(() => {\n      ${IS_VISIBLE_JS}\n      const inputs = Array.from(document.querySelectorAll('input[type=\"text\"], input[type=\"search\"], input:not([type])')).filter(isVisible);\n      const input = inputs[inputs.length - 1];\n      if (!input) return { ok: false, reason: 'No input visible.' };\n      const setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;\n      setter.call(input, ${JSON.stringify(query)});\n      input.dispatchEvent(new Event('input', { bubbles: true }));\n      input.dispatchEvent(new Event('change', { bubbles: true }));\n      return { ok: true };\n    })()`);\n        if (!fillRes?.ok) throw new CommandExecutionError(fillRes?.reason || 'search type failed', '');\n        await page.wait(0.8);\n        const items = requireArrayResult(await evaluateQoder(page, `(() => {\n      ${IS_VISIBLE_JS}\n      // Search palette results: prefer [role=option], else any clickable row in the modal.\n      const opts = Array.from(document.querySelectorAll('[role=\"option\"], [role=\"menuitem\"]')).filter(isVisible);\n      const titles = opts.map((o) => {\n        // Codex-style fix: text may be in per-char spans; use textContent.\n        const titleEl = o.querySelector('.truncate, [class*=\"title\"i]') || o;\n        return (titleEl.textContent || '').trim().replace(/\\\\s+/g, ' ').slice(0, 200);\n      }).filter(Boolean);\n      return [...new Set(titles)];\n    })()`), 'qoder search');\n        try { await page.evaluate(`document.body.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));`); } catch {}\n        if (!items.length) {\n            throw new EmptyResultError('qoder search', `No items matched \"${query}\".`);\n        }\n        return items.slice(0, limit).map((t, i) => ({ Index: i + 1, Item: t }));\n    },","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/qoder/ui.js#L74-L110","documentation":"Thrown by the qoder search command when the fill script — which finds the last visible text/search input, sets its value via the native setter, and dispatches input/change events — fails. fillRes.ok being false usually means no visible input was found in the open search palette. Without the query being typed, results never appear.","triggerScenarios":"The search palette opened but contains no input matching input[type=\"text\"], input[type=\"search\"], or input without type; the palette uses a contenteditable or custom editor instead of <input>; the input is not visible (display:none during animation); the palette didn't actually open.","commonSituations":"Qoder update switching to a custom combobox component; palette mount animation making the input temporarily invisible when the script runs; headless rendering differences; palette closed by an earlier Escape/blur.","solutions":["Add a short wait after opening the palette so the input finishes mounting/animating in.","Extend the input selector list to cover contenteditable and role=textbox: '[contenteditable=\"true\"], [role=\"textbox\"]'.","Verify the palette is open before typing (check for the modal element).","Update selectors to match the current Qoder search input markup."],"exampleFix":"// before\nconst inputs = Array.from(document.querySelectorAll('input[type=\"text\"], input[type=\"search\"], input:not([type])')).filter(isVisible);\n// after\nawait page.wait(0.3);\nconst inputs = Array.from(document.querySelectorAll('input[type=\"text\"], input[type=\"search\"], input:not([type]), [role=\"textbox\"], [contenteditable=\"true\"]')).filter(isVisible);","handlingStrategy":"retry","validationCode":"const paletteOpen = await page.evaluate(`!!document.querySelector('[role=\"dialog\"], [class*=\"palette\"], [class*=\"modal\"]')`);\nif (!paletteOpen) throw new Error('Search palette did not open; cannot type');","typeGuard":"function foundVisibleInput(sel) { return Boolean(document.querySelector(sel) && document.querySelector(sel).offsetParent !== null); }","tryCatchPattern":"try {\n  await search(page, query);\n} catch (e) {\n  if (/search type failed/.test(String(e.message))) {\n    await page.wait(1);\n    return search(page, query);\n  }\n  throw e;\n}","preventionTips":["Wait for the palette animation to finish before typing.","Include contenteditable/[role=textbox] in the input selector list.","Verify the palette is open before running the fill script.","Escape and reopen the palette if a previous attempt left it in a bad state."],"tags":["ui-automation","dom-selector","input-fill"],"backgroundTag":"selector-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}