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 the

View on GitHub (pinned to 94993f7401)

Solutions

  1. Use `--clip` alone to capture a fixed region of the page.
  2. Use a selector/`@ref` alone to capture a specific element (the element's bounding box is used automatically).
  3. 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

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


AI-assisted analysis of garrytan/gstack@94993f7401 (2026-08-12). Data as JSON: /api/errors/b55eedb798f8b208. Report an issue: GitHub.