garrytan/gstack · error · Error
Frame not found: ${target}
Error message
Frame not found: ${target} What it means
After resolving the target via `--name`, `--url`, or an element selector/ref, the command checks whether a `Frame` was found (line 1029). If Playwright returned null — no frame matched the name/URL, or the resolved element had no content frame — the command throws, echoing the target. The command then sets the frame and clears refs only on success.
Source
Thrown at browse/src/meta-commands.ts:1029
const page = bm.getPage();
let frame: Frame | null = null;
if (target === '--name') {
if (!args[1]) throw new Error('Usage: frame --name <name>');
frame = page.frame({ name: args[1] });
} else if (target === '--url') {
if (!args[1]) throw new Error('Usage: frame --url <pattern>');
frame = page.frame({ url: new RegExp(escapeRegExp(args[1])) });
} else {
// CSS selector or @ref for the iframe element
const resolved = await bm.resolveRef(target);
const locator = 'locator' in resolved ? resolved.locator : page.locator(resolved.selector);
const elementHandle = await locator.elementHandle({ timeout: 5000 });
frame = await elementHandle?.contentFrame() ?? null;
await elementHandle?.dispose();
}
if (!frame) throw new Error(`Frame not found: ${target}`);
bm.setFrame(frame);
bm.clearRefs();
return `Switched to frame: ${frame.url()}`;
}
// ─── UX Audit ─────────────────────────────────────
case 'ux-audit': {
const page = bm.getPage();
// Extract page structure for UX behavioral analysis
// Agent interprets the data and applies Krug's 6 usability tests
// Uses textContent (not innerText) to avoid layout computation on large DOMs
const data = await page.evaluate(() => {
const HEADING_CAP = 50;
const INTERACTIVE_CAP = 200;
const TEXT_BLOCK_CAP = 50;
// Site ID: logo or brand elementView on GitHub (pinned to 94993f7401)
Solutions
- Verify the iframe exists with a `snapshot`/`text` first; wait for it if it loads lazily.
- Check the frame name/URL against the page's actual frames (e.g. via `cdp` or DOM inspection).
- Ensure the element ref points to an `<iframe>` element, not a wrapper `<div>`.
- For dynamic frames, retry after the iframe's network request settles.
Example fix
// before browse frame @e5 // @e5 is a div, not an iframe // after browse frame iframe.widget
Defensive patterns
Strategy: try-catch
Validate before calling
// Best-effort: confirm the iframe exists before switching.
const frames = bm.getPage().frames();
const matches = frames.filter(f => /* name/url/selector logic */);
if (matches.length === 0) throw new Error('No matching frame; page may still be loading'); Try / catch
try { await browse.frame(target); }
catch (err) {
if (/Frame not found/.test(err.message)) {
await bm.getPage().waitForLoadState('networkidle', { timeout: 3000 }).catch(() => {});
return browse.frame(target); // single retry after settle
}
throw err;
} Prevention
- Wait for the iframe element to attach before calling `frame`.
- Prefer `--name`/`--url` for stable identification over element refs that can shift.
- Confirm the target element is actually an `<iframe>` before resolving by ref.
When it happens
Trigger: `browse frame --name nope`, `browse frame --url 'does-not-exist\.com'`, or `browse frame @e5` where `@e5` is not an `<iframe>`/has no content frame.
Common situations: iframes loading asynchronously (frame not yet present), wrong name/URL pattern, element ref pointing to a non-iframe, cross-origin frames Playwright cannot enumerate, or a frame that has navigated away.
Related errors
- Cannot promote: no skill for ${normalized} in project ${proj
- Cannot delete: no skill for ${normalized} in ${scope} scope.
- State not found: ${statePath}
- Usage: frame <selector|@ref|--name name|--url pattern|main>
- Usage: frame --name <name>
AI-assisted analysis of garrytan/gstack@94993f7401 (2026-08-12).
Data as JSON: /api/errors/73e11b8cbafdfb5f.
Report an issue: GitHub.