garrytan/gstack · warning · Error

Usage: browse viewport [<WxH>] [--scale <n>] (e.g. 375x812,

Error message

Usage: browse viewport [<WxH>] [--scale <n>]  (e.g. 375x812, or --scale 2 to keep current size)

What it means

Thrown by the `browse viewport` command when it is invoked with no arguments at all. The command requires either a size token (e.g. `375x812`) or a `--scale <n>` flag (or both); when both `sizeArg` and `scaleArg` stay `undefined` after the arg-parsing loop, the command cannot determine what viewport change to make and refuses to proceed. The message is a usage hint pointing the caller to the two accepted forms.

Source

Thrown at browse/src/write-commands.ts:526

          if (val === undefined || val === '') {
            throw new Error('viewport --scale: missing value. Usage: viewport [WxH] --scale <n>');
          }
          const parsed = Number(val);
          if (!Number.isFinite(parsed)) {
            throw new Error(`viewport --scale: value '${val}' is not a finite number.`);
          }
          scaleArg = parsed;
        } else if (args[i].startsWith('--')) {
          throw new Error(`Unknown viewport flag: ${args[i]}`);
        } else if (sizeArg === undefined) {
          sizeArg = args[i];
        } else {
          throw new Error(`Unexpected positional arg: ${args[i]}. Usage: viewport [WxH] [--scale <n>]`);
        }
      }

      if (sizeArg === undefined && scaleArg === undefined) {
        throw new Error('Usage: browse viewport [<WxH>] [--scale <n>]  (e.g. 375x812, or --scale 2 to keep current size)');
      }

      // Resolve width/height: either from sizeArg or from current viewport if --scale-only.
      let w: number, h: number;
      if (sizeArg) {
        if (!sizeArg.includes('x')) throw new Error('Usage: browse viewport [<WxH>] [--scale <n>] (e.g., 375x812)');
        const [rawW, rawH] = sizeArg.split('x').map(Number);
        w = Math.min(Math.max(Math.round(rawW) || 1280, 1), 16384);
        h = Math.min(Math.max(Math.round(rawH) || 720, 1), 16384);
      } else {
        // --scale without WxH → use BrowserManager's tracked viewport (source of truth
        // since setViewport + launchContext keep it in sync). Falls back reliably on
        // headed → headless transitions or contexts with viewport:null.
        const current = bm.getCurrentViewport();
        w = current.width;
        h = current.height;
      }

View on GitHub (pinned to 94993f7401)

Solutions

  1. Pass at least one argument: a size token or `--scale <n>` (e.g. `browse viewport 375x812`).
  2. If you only want to change DPR without resizing, use `browse viewport --scale 2` — the current tracked viewport is reused.
  3. If you intended to read the current viewport rather than set it, use the read-side command (e.g. `browse info` or the snapshot command) instead of `browse viewport`.
  4. Inspect the args array your caller is forwarding and ensure it is non-empty before dispatching the command.

Example fix

// before
await runBrowseCommand(['viewport']);

// after
await runBrowseCommand(['viewport', '375x812']);
// or
await runBrowseCommand(['viewport', '--scale', '2']);
Defensive patterns

Strategy: validation

Validate before calling

function validateViewportArgs(args: string[]): void {
  const hasScale = args.includes('--scale');
  const hasSize = args.some(a => !a.startsWith('--') && a.includes('x'));
  if (!hasScale && !hasSize) {
    throw new Error('viewport requires a WxH size or --scale <n>');
  }
}
// call before: runBrowseCommand(['viewport', ...args])

Type guard

function isNonEmptyViewportArgs(args: unknown): args is [string, ...string[]] {
  return Array.isArray(args) && args.length > 0 && args.every(a => typeof a === 'string');
}

Prevention

When it happens

Trigger: Calling `browse viewport` with an empty args array; calling it with only whitespace tokens that the parser does not classify as a positional; a wrapper script that forwards an unpopulated variable as the viewport payload.

Common situations: An AI agent or shell wrapper builds the viewport command dynamically and the variable holding the dimensions resolves to empty; a user runs `browse viewport` expecting an interactive prompt or a status readout instead of a setter; a typo'd flag like `browse viewport --size 375x812` is consumed as an unknown flag and never sets sizeArg/scaleArg.

Related errors


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