{"record":{"id":"6d6ba76954e9028e","repo":"garrytan/gstack","slug":"cannot-use-viewport-with-clip-choose-one","errorCode":null,"errorMessage":"Cannot use --viewport with --clip — choose one","messagePattern":"Cannot use --viewport with --clip — choose one","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"browse/src/meta-commands.ts","lineNumber":496,"sourceCode":"          outputPath = arg;\n        }\n      }\n\n      // --selector flag takes precedence; conflict with positional selector.\n      if (flagSelector !== undefined) {\n        if (targetSelector !== undefined) {\n          throw new Error('--selector conflicts with positional selector — choose one');\n        }\n        targetSelector = flagSelector;\n      }\n\n      validateOutputPath(outputPath);\n\n      if (clipRect && targetSelector) {\n        throw new Error('Cannot use --clip with a selector/ref — choose one');\n      }\n      if (viewportOnly && clipRect) {\n        throw new Error('Cannot use --viewport with --clip — choose one');\n      }\n\n      // --base64 mode: capture to buffer instead of disk\n      if (base64Mode) {\n        let buffer: Buffer;\n        if (targetSelector) {\n          const resolved = await bm.resolveRef(targetSelector);\n          const locator = 'locator' in resolved ? resolved.locator : page.locator(resolved.selector);\n          buffer = await locator.screenshot({ timeout: 5000 });\n        } else if (clipRect) {\n          buffer = await page.screenshot({ clip: clipRect });\n        } else {\n          buffer = await page.screenshot({ fullPage: !viewportOnly });\n          // Guard the most common API-bricking case (fullPage). Element /\n          // clip captures usually stay within the cap; we still guard the\n          // path-mode below for fullPage writes.\n          ({ buffer } = await guardScreenshotBuffer(buffer));\n        }","sourceCodeStart":478,"sourceCodeEnd":514,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/meta-commands.ts#L478-L514","documentation":"Thrown when both `--viewport` and `--clip` are passed to `screenshot`. `--viewport` means 'capture only the visible viewport' (Playwright `fullPage:false`) while `--clip` supplies an explicit rectangle; supplying both is contradictory, so the guard at lines 495-496 rejects it before calling Playwright.","triggerScenarios":"`browse screenshot --viewport --clip 0,0,800,600 out.png` (lines 495-496).","commonSituations":"Confusing `--viewport` (visible-area capture) with `--clip` (arbitrary rectangle), or leaving a stale `--viewport` in a parameterized call.","solutions":["Keep `--clip x,y,w,h` and remove `--viewport` to capture an explicit rectangle.","Keep `--viewport` and remove `--clip` to capture only the visible viewport.","For a full-page capture, remove both flags (full page is the default)."],"exampleFix":"// before\nbrowse screenshot --viewport --clip 0,0,800,600 out.png\n// after\nbrowse screenshot --clip 0,0,800,600 out.png","handlingStrategy":"validation","validationCode":"if (args.includes('--viewport') && args.includes('--clip')) {\n  throw new Error('--viewport and --clip are mutually exclusive');\n}","typeGuard":null,"tryCatchPattern":"try { await browse.screenshot(args); }\ncatch (err) {\n  if (/Cannot use --viewport with --clip/.test(err.message)) {\n    args = args.filter(a => a !== '--viewport'); // pick one\n  }\n}","preventionTips":["Treat screenshot mode as an enum in your wrapper: fullPage | viewport | clip.","Never template both flags from independent booleans."],"tags":["screenshot","argument-parsing","conflict"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}