garrytan/gstack · error · Error

Usage: browse diff <url1> <url2>

Error message

Usage: browse diff <url1> <url2>

What it means

The `diff` meta-command requires exactly two URL arguments (`url1`, `url2`) so it can navigate to each in turn and compare their cleaned text via `Diff.diffLines` (lines 715-728). If either argument is missing the command throws this usage error before any network navigation.

Source

Thrown at browse/src/meta-commands.ts:717

            results.push(`[${label}] ${result}`);
          } catch (err: any) {
            results.push(`[${label}] ERROR: ${err.message}`);
          }
        }
      }

      // Wait for network to settle after write commands before returning
      if (lastWasWrite) {
        await bm.getPage().waitForLoadState('networkidle', { timeout: 2000 }).catch(() => {});
      }

      return results.join('\n\n');
    }

    // ─── Diff ──────────────────────────────────────────
    case 'diff': {
      const [url1, url2] = args;
      if (!url1 || !url2) throw new Error('Usage: browse diff <url1> <url2>');

      const page = bm.getPage();
      const normalizedUrl1 = await validateNavigationUrl(url1);
      await page.goto(normalizedUrl1, { waitUntil: 'domcontentloaded', timeout: 15000 });
      const text1 = await getCleanText(page);

      const normalizedUrl2 = await validateNavigationUrl(url2);
      await page.goto(normalizedUrl2, { waitUntil: 'domcontentloaded', timeout: 15000 });
      const text2 = await getCleanText(page);

      const changes = Diff.diffLines(text1, text2);
      const output: string[] = [`--- ${url1}`, `+++ ${url2}`, ''];

      for (const part of changes) {
        const prefix = part.added ? '+' : part.removed ? '-' : ' ';
        const lines = part.value.split('\n').filter(l => l.length > 0);
        for (const line of lines) {
          output.push(`${prefix} ${line}`);

View on GitHub (pinned to 94993f7401)

Solutions

  1. Supply both URLs: `browse diff https://prod.example.com https://staging.example.com`.
  2. Quote URLs containing spaces, query params with `&`, or shell metacharacters.
  3. If you intended a single-page snapshot comparison, use `state save`/`state load` or external diff tooling instead.

Example fix

// before
browse diff https://example.com
// after
browse diff https://example.com https://staging.example.com
Defensive patterns

Strategy: validation

Validate before calling

if (args.length < 2 || !args[0] || !args[1]) {
  throw new Error('diff requires exactly two URL arguments');
}
if (!/^https?:\/\//.test(args[0]) || !/^https?:\/\//.test(args[1])) {
  throw new Error('diff arguments must be absolute http(s) URLs');
}

Type guard

const isUrl = (s: unknown): s is string =>
  typeof s === 'string' && /^https?:\/\//.test(s);

Try / catch

try { await browse.diff(url1, url2); }
catch (err) {
  if (/Usage: browse diff/.test(err.message)) {
    // prompt the caller for the missing URL
  }
}

Prevention

When it happens

Trigger: Calling `browse diff https://a.example.com` (missing second URL) or `browse diff` with no args (line 716-717).

Common situations: Shell quoting that dropped one URL, an agent templating only one URL into the call, or comparing a URL against an empty baseline.

Related errors


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