garrytan/gstack · warning · Error

Usage: browse header <name>:<value>

Error message

Usage: browse header <name>:<value>

What it means

Thrown by `browse header` when the first argument is missing or does not contain a `:` character. The command splits on the first `:` to derive header name and value; without a colon it cannot determine the boundary and rejects the input. This is the header counterpart to the cookie command's `=` requirement.

Source

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

    case 'cookie': {
      const cookieStr = args[0];
      if (!cookieStr || !cookieStr.includes('=')) throw new Error('Usage: browse cookie <name>=<value>');
      const eq = cookieStr.indexOf('=');
      const name = cookieStr.slice(0, eq);
      const value = cookieStr.slice(eq + 1);
      const url = new URL(page.url());
      await page.context().addCookies([{
        name,
        value,
        domain: url.hostname,
        path: '/',
      }]);
      return `Cookie set: ${name}=****`;
    }

    case 'header': {
      const headerStr = args[0];
      if (!headerStr || !headerStr.includes(':')) throw new Error('Usage: browse header <name>:<value>');
      const sep = headerStr.indexOf(':');
      const name = headerStr.slice(0, sep).trim();
      const value = headerStr.slice(sep + 1).trim();
      await bm.setExtraHeader(name, value);
      const sensitiveHeaders = ['authorization', 'cookie', 'set-cookie', 'x-api-key', 'x-auth-token'];
      const redactedValue = sensitiveHeaders.includes(name.toLowerCase()) ? '****' : value;
      return `Header set: ${name}: ${redactedValue}`;
    }

    case 'useragent': {
      const ua = args.join(' ');
      if (!ua) throw new Error('Usage: browse useragent <string>');
      bm.setUserAgent(ua);
      const error = await bm.recreateContext();
      if (error) {
        return `User agent set to "${ua}" but: ${error}`;
      }
      return `User agent set: ${ua}`;

View on GitHub (pinned to 94993f7401)

Solutions

  1. Provide the token as `name:value`: `browse header X-Custom:foo`.
  2. Only the FIRST colon is the separator, so values containing colons (URLs, times) are fine: `browse header Referer:https://example.com`.
  3. If you meant to set a cookie, use `browse cookie name=value`.
  4. Sensitive header names (authorization, cookie, set-cookie, x-api-key, x-auth-token) are redacted to `****` in the success message — the value is still applied, only the echo is masked.

Example fix

// before
await runBrowseCommand(['header', 'X-Custom=foo']);

// after
await runBrowseCommand(['header', 'X-Custom:foo']);
Defensive patterns

Strategy: validation

Validate before calling

function parseHeaderToken(token: string): { name: string; value: string } {
  if (!token || !token.includes(':')) {
    throw new Error('header token must be name:value');
  }
  const sep = token.indexOf(':');
  return { name: token.slice(0, sep).trim(), value: token.slice(sep + 1).trim() };
}

Type guard

function isHeaderToken(s: string): boolean {
  return typeof s === 'string' && s.includes(':');
}

Prevention

When it happens

Trigger: Calling `browse header` with no args; `browse header X-Custom` (value omitted); `browse header X-Custom=foo` (used `=` instead of `:`); a value that legitimately contains no colon because the user passed only the name.

Common situations: User conflates header (`:`) and cookie (`=`) syntax; an agent copies a fetch options object (`{ 'X-Custom': 'foo' }`) and emits `X-Custom foo` losing the separator; setting a header whose value contains a URL (`Referer: https://...`) works because only the first `:` is the split point — the user incorrectly assumes the URL's `://` breaks parsing and pre-trims.

Related errors


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