jackwener/OpenCLI · error · Error
No element found matching selector: ${query}
Error message
No element found matching selector: ${query} What it means
setFileInputFiles first probes the page with Runtime.evaluate to confirm the selector matches an element; if document.querySelector finds nothing, it throws 'No element found matching selector'. This fails fast before attempting the file-chooser interception dance required by chrome.debugger attachments.
Source
Thrown at extension/src/cdp.ts:362
export async function setFileInputFiles(
tabId: number,
files: string[],
selector?: string,
): Promise<void> {
await ensureAttached(tabId);
// Enable DOM + Page domains. Page is needed for file-chooser interception.
await sendDebuggerCommand({ tabId }, 'DOM.enable');
await sendDebuggerCommand({ tabId }, 'Page.enable');
// Find the file input element (used to trigger the chooser).
const query = selector || 'input[type="file"]';
const found = await sendDebuggerCommand({ tabId }, 'Runtime.evaluate', {
expression: `!!document.querySelector(${JSON.stringify(query)})`,
returnByValue: true,
}) as { result?: { value?: boolean } };
if (!found.result?.value) {
throw new Error(`No element found matching selector: ${query}`);
}
// Chrome rejects DOM.setFileInputFiles with a plain nodeId/backendNodeId when
// the debugger is attached via chrome.debugger (crbug 928255, "-32000 Not
// allowed"). The only accepted path is file-chooser interception: enable it,
// programmatically open the chooser, and use the backendNodeId that the
// intercepted Page.fileChooserOpened event hands back. See issue #2108.
await sendDebuggerCommand({ tabId }, 'Page.setInterceptFileChooserDialog', { enabled: true });
try {
const backendNodeId = await new Promise<number>((resolve, reject) => {
const timer = setTimeout(() => {
cleanup();
reject(new Error('Page.fileChooserOpened not received within 5s — the input may not have opened a file chooser'));
}, 5000);
const listener = (source: chrome.debugger.Debuggee, method: string, params: unknown) => {
if (source.tabId !== tabId || method !== 'Page.fileChooserOpened') return;
// This is our chooser event — settle now either way, so a malformed
// event rejects immediately instead of hanging until the 5s timeout.View on GitHub (pinned to 49907e53dc)
Solutions
- Verify the selector matches in DevTools console: document.querySelector('…')
- Wait for the upload UI to render before calling setFileInputFiles
- Click the button that injects the file input first, then set the files
- Target the correct frame if the input lives in an iframe (the probe runs in the main frame)
- Use the default selector by passing an empty selector only when exactly one file input exists
Example fix
// before
await cdp.setFileInputFiles(tabId, files, 'input.upload'); // input not yet in DOM
// after
await cdp.evaluate(tabId, "!!document.querySelector('input.upload') || document.querySelector('#add')?.click()");
await new Promise(r => setTimeout(r, 500)); // let it render
await cdp.setFileInputFiles(tabId, files, 'input.upload'); Defensive patterns
Strategy: validation
Validate before calling
const found = await cdp.evaluate(tabId, `!!document.querySelector(${JSON.stringify(selector)})`);
if (found !== true) throw new Error(`pre-check failed: ${selector} not in DOM`); Type guard
function selectorExists(v: unknown): v is true {
return v === true;
} Try / catch
try {
await cdp.setFileInputFiles(tabId, files, selector);
} catch (e) {
if ((e as Error).message.startsWith('No element found matching selector')) {
await waitForSelector(tabId, selector);
return retry();
}
throw e;
} Prevention
- Wait for the upload UI to render before setting files
- Click the trigger button that injects the input first
- Account for shadow DOM/iframes — the probe only sees the main frame document
- Verify selectors in DevTools console on the exact page state
- Prefer stable ids/data attributes over generated class names
When it happens
Trigger: handleSetFileInput is called with a selector (default 'input[type="file"]') that matches no element in the current DOM of the attached tab.
Common situations: The file input is inside a shadow DOM or iframe that document.querySelector can't see; the page hasn't rendered the uploader yet; selector typo; the input is only added after clicking an 'Upload' button.
Related errors
- DOM node not found
- Could not find Antigravity input box
- Could not find input box
- Could not find antigravity.agentSidePanelInputBox
- Could not find Antigravity input box
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/348adbcee246dbb0.
Report an issue: GitHub.