garrytan/gstack · error · Error
Cannot use --clip with a selector/ref — choose one
Error message
Cannot use --clip with a selector/ref — choose one
What it means
Thrown when `--clip x,y,w,h` and an element target (positional selector or `@ref`, or `--selector`) are both supplied. Playwright cannot capture a clip rectangle AND an element locator simultaneously — they are mutually exclusive capture modes. The guard at lines 492-494 fires before any Playwright call.
Source
Thrown at browse/src/meta-commands.ts:493
} else if (arg.startsWith('@e') || arg.startsWith('@c') || arg.startsWith('.') || arg.startsWith('#') || arg.includes('[')) {
targetSelector = arg;
} else {
outputPath = arg;
}
}
// --selector flag takes precedence; conflict with positional selector.
if (flagSelector !== undefined) {
if (targetSelector !== undefined) {
throw new Error('--selector conflicts with positional selector — choose one');
}
targetSelector = flagSelector;
}
validateOutputPath(outputPath);
if (clipRect && targetSelector) {
throw new Error('Cannot use --clip with a selector/ref — choose one');
}
if (viewportOnly && clipRect) {
throw new Error('Cannot use --viewport with --clip — choose one');
}
// --base64 mode: capture to buffer instead of disk
if (base64Mode) {
let buffer: Buffer;
if (targetSelector) {
const resolved = await bm.resolveRef(targetSelector);
const locator = 'locator' in resolved ? resolved.locator : page.locator(resolved.selector);
buffer = await locator.screenshot({ timeout: 5000 });
} else if (clipRect) {
buffer = await page.screenshot({ clip: clipRect });
} else {
buffer = await page.screenshot({ fullPage: !viewportOnly });
// Guard the most common API-bricking case (fullPage). Element /
// clip captures usually stay within the cap; we still guard theView on GitHub (pinned to 94993f7401)
Solutions
- Use `--clip` alone to capture a fixed region of the page.
- Use a selector/`@ref` alone to capture a specific element (the element's bounding box is used automatically).
- If you need a sub-region of an element, capture the element then crop the PNG in post-processing.
Example fix
// before browse screenshot --clip 0,0,200,200 .hero // after browse screenshot .hero
Defensive patterns
Strategy: validation
Validate before calling
const hasClip = args.includes('--clip');
const hasSelector = args.includes('--selector') ||
args.some(a => /^(?:@e|@c|\.|#|\[)/.test(a));
if (hasClip && hasSelector) throw new Error('--clip and selector are mutually exclusive'); Try / catch
try { await browse.screenshot(args); }
catch (err) {
if (/Cannot use --clip with a selector/.test(err.message)) {
// drop --clip OR the selector and retry based on intent
}
} Prevention
- Decide capture mode (element vs region) before building args.
- Model the screenshot request as a discriminated union in your wrapper so clip+selector can't coexist.
When it happens
Trigger: `browse screenshot --clip 0,0,100,100 .hero` or `browse screenshot --clip 0,0,100,100 --selector #nav` (lines 492-493).
Common situations: Trying to 'crop' an element capture with `--clip`, or copy-pasting a clip invocation and appending a selector for context.
Related errors
- --selector conflicts with positional selector — choose one
- Cannot use --viewport with --clip — choose one
- Usage: screenshot --selector <css> [path]
- Usage: screenshot --clip x,y,w,h [path]
- Unknown screenshot flag: ${args[i]}
AI-assisted analysis of garrytan/gstack@94993f7401 (2026-08-12).
Data as JSON: /api/errors/b55eedb798f8b208.
Report an issue: GitHub.