garrytan/gstack · warning · Error

Usage: browse style <sel> <prop> <value> | style --undo [N]

Error message

Usage: browse style <sel> <prop> <value> | style --undo [N]

What it means

Thrown by `browse style` when the non-`--undo` form is invoked without all three required tokens: selector, property, and a non-empty value. The command destructures `[selector, property, ...valueParts]` and joins the remaining parts into `value`; if any of selector/property/value is missing/empty, it cannot form a valid CSS declaration and refuses to proceed.

Source

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

        if (err?.code !== 'ENOENT' && !err?.message?.includes('spawn')) throw err;
      }

      return `Cookie picker opened at http://127.0.0.1:${port}/cookie-picker\nDetected browsers: ${browsers.map(b => b.name).join(', ')}\nSelect domains to import, then close the picker when done.\n\nTip: For scripted imports, use --domain <domain> to scope cookies to a single domain.`;
    }

    case 'style': {
      // style --undo [N] → revert modification
      if (args[0] === '--undo') {
        const idx = args[1] ? parseInt(args[1], 10) : undefined;
        await undoModification(page, idx);
        return idx !== undefined ? `Reverted modification #${idx}` : 'Reverted last modification';
      }

      // style <selector> <property> <value>
      const [selector, property, ...valueParts] = args;
      const value = valueParts.join(' ');
      if (!selector || !property || !value) {
        throw new Error('Usage: browse style <sel> <prop> <value> | style --undo [N]');
      }

      // Validate CSS property name
      if (!/^[a-zA-Z-]+$/.test(property)) {
        throw new Error(`Invalid CSS property name: ${property}. Only letters and hyphens allowed.`);
      }

      // Validate CSS value — block data exfiltration patterns
      const DANGEROUS_CSS = /url\s*\(|expression\s*\(|@import|javascript:|data:/i;
      if (DANGEROUS_CSS.test(value)) {
        throw new Error('CSS value rejected: contains potentially dangerous pattern.');
      }

      const mod = await modifyStyle(page, selector, property, value);
      return `Style modified: ${selector} { ${property}: ${mod.oldValue || '(none)'} → ${value} } (${mod.method})`;
    }

    case 'cleanup': {

View on GitHub (pinned to 94993f7401)

Solutions

  1. Provide all three tokens: `browse style body color red`.
  2. For multi-word values, pass them as separate args — they are joined with spaces: `browse style body font-family Arial sans-serif`.
  3. To revert a prior change, use `browse style --undo` or `browse style --undo <N>`.
  4. Quote the value if your shell would otherwise split it incorrectly.

Example fix

// before
await runBrowseCommand(['style', 'body', 'color']);

// after
await runBrowseCommand(['style', 'body', 'color', 'red']);
Defensive patterns

Strategy: validation

Validate before calling

function validateStyleArgs(args: string[]): { selector: string; property: string; value: string } {
  const [selector, property, ...valueParts] = args;
  const value = valueParts.join(' ').trim();
  if (!selector || !property || !value) {
    throw new Error('style requires <selector> <property> <value>');
  }
  return { selector, property, value };
}

Type guard

function isStyleArgs(args: unknown): args is [string, string, string, ...string[]] {
  return Array.isArray(args) && typeof args[0] === 'string' && typeof args[1] === 'string' && args.length >= 3 && args.slice(2).join('').length > 0;
}

Prevention

When it happens

Trigger: Calling `browse style` with no args; `browse style body` (property and value missing); `browse style body color` (value missing); `browse style body color ''` (value joins to empty string); a wrapper that split on whitespace and dropped a value containing only spaces.

Common situations: An agent emits a two-token style command assuming a default value; a user expects the command to toggle or read styles rather than set them; copy-paste lost the value when it was on a separate line; the value was a CSS variable like `var(--x)` but got URL-encoded or stripped.

Related errors


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