can1357/oh-my-pi · error · Error

No element matched ${spec.raw}

Error message

No element matched ${spec.raw}

What it means

CmuxTab's selector actions build an in-page script that calls findElement(spec); when no element matches the selector spec, the page side throws 'No element matched <spec.raw>', surfaced as this ToolError. This is the generic 'selector did not match anything' error for click/fill/type/check/select/exists-style actions on the cmux surface.

Source

Thrown at packages/coding-agent/src/tools/browser/cmux/cmux-tab.ts:910

					await this.#request("browser.scroll_into_view", { selector: nativeSelector });
					return undefined as TResult;
			}
		}
		return await this.#evalSelectorAction<TResult>(spec, action, args);
	}

	async #evalSelectorAction<TResult>(
		spec: SelectorSpec,
		action: string,
		args: Record<string, unknown>,
	): Promise<TResult> {
		const script = `(() => {
			const spec = ${JSON.stringify(spec)};
			const action = ${JSON.stringify(action)};
			const args = ${JSON.stringify(args)};
			${PAGE_SELECTOR_HELPERS}
			const element = findElement(spec);
			if (!element) throw new Error("No element matched " + spec.raw);
			if (action !== "exists") element.scrollIntoView({ block: "center", inline: "center" });
			switch (action) {
				case "click":
					mouseEvent(element, "mousedown");
					mouseEvent(element, "mouseup");
					if (typeof element.click === "function") element.click();
					else mouseEvent(element, "click");
					return true;
				case "dblclick":
					mouseEvent(element, "dblclick");
					return true;
				case "hover":
					mouseEvent(element, "mouseover");
					mouseEvent(element, "mouseenter");
					mouseEvent(element, "mousemove");
					return true;
				case "focus":
					if (typeof element.focus === "function") element.focus();

View on GitHub (pinned to 9690622007)

Solutions

  1. Wait for the element first: await tab.waitForSelector(sel) (with a generous timeout) before performing the action.
  2. Verify the selector matches by testing it in-page: tab.evaluate((s) => !!document.querySelector(s), sel), and adjust (prefer data-testid or id).
  3. Check whether the element lives in an iframe or shadow root — switch to the right frame or use a deep/role-based selector the helpers support.
  4. Re-check for typos and dynamic text: copy the exact visible label/attribute from a live tab.evaluate(document.body.innerHTML) snapshot.

Example fix

// before: act immediately, element not yet mounted
await tab.fill("#email", "user@example.com");
// after: wait for the element, then act
await tab.waitForSelector("#email", { timeout: 10_000 });
await tab.fill("#email", "user@example.com");
Defensive patterns

Strategy: validation

Validate before calling

const matches = await tab.evaluate(
  (sel) => document.querySelectorAll(sel).length,
  "#email",
);
if (matches === 0) await tab.waitForSelector("#email", { timeout: 10_000 });

Try / catch

try {
  await tab.fill("#email", "user@example.com");
} catch (err) {
  if (err instanceof ToolError && err.message.startsWith("No element matched")) {
    await tab.waitForSelector("#email", { timeout: 10_000 });
    await tab.fill("#email", "user@example.com");
  } else throw err;
}

Prevention

When it happens

Trigger: Calling tab.click/tab.fill/tab.type/tab.select/tab.check with a CSS selector, text selector, or role spec that matches no element at action time: typo in the selector, element inside an iframe not reachable by the helper, element not yet rendered, wrong frame/page, or selector depending on auto-generated attributes that changed.

Common situations: Selectors written for a different DOM state (before login, before modal opens); framework class-name hashing changing between environments; elements in shadow DOM or iframes the PAGE_SELECTOR_HELPERS don't traverse; React 18 concurrent rendering delaying mount past the action; using text-match selectors whose label text changed (i18n, whitespace).

Related errors


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