garrytan/gstack · warning · Error

--out specified more than once

Error message

--out specified more than once

What it means

Thrown by parseOutArgs when `--out <path>` (space-separated form) appears a second time in the same js/eval command. The parser tracks the first outPath and refuses a second to avoid a silent overwrite of the output target.

Source

Thrown at browse/src/read-commands.ts:72

}

/**
 * Parse `--out <path>` / `--out=<path>` and `--raw` / `--raw=true|false` out of an
 * arg list, returning the flags plus the remaining positional args (`rest`).
 *
 * Single source of truth shared by the js/eval handlers and the write-capability
 * gate in server.ts, so the two never disagree on what counts as an `--out`
 * invocation. Throws on malformed usage (repeated `--out`, missing value, bad
 * `--raw` value) so the user gets a clear error instead of a silent misparse.
 */
export function parseOutArgs(args: string[]): OutArgs {
  let outPath: string | undefined;
  let raw = false;
  const rest: string[] = [];
  for (let i = 0; i < args.length; i++) {
    const a = args[i];
    if (a === '--out') {
      if (outPath !== undefined) throw new Error('--out specified more than once');
      const val = args[i + 1];
      if (val === undefined || val.startsWith('--')) throw new Error('--out requires a file path');
      outPath = val;
      i++;
    } else if (a.startsWith('--out=')) {
      if (outPath !== undefined) throw new Error('--out specified more than once');
      const val = a.slice('--out='.length);
      if (val === '') throw new Error('--out requires a file path');
      outPath = val;
    } else if (a === '--raw') {
      raw = true;
    } else if (a.startsWith('--raw=')) {
      const v = a.slice('--raw='.length).toLowerCase();
      if (v !== 'true' && v !== 'false') throw new Error('--raw must be true or false');
      raw = v === 'true';
    } else {
      rest.push(a);
    }

View on GitHub (pinned to 94993f7401)

Solutions

  1. Remove the duplicate --out — only one output path is allowed per command
  2. Audit wrapper scripts and aliases that append --out automatically
  3. Use --out=path form exactly once, explicitly
  4. Build arg arrays with a Set or guard rather than naive push

Example fix

// before
browse js 'document.title' --out a.json --out b.json  // throws

// after
browse js 'document.title' --out a.json
Defensive patterns

Strategy: validation

Validate before calling

function hasSingleOutArg(args: string[]): boolean {
  return args.filter(a => a === '--out' || a.startsWith('--out=')).length <= 1;
}

if (!hasSingleOutArg(args)) {
  throw new Error('Only one --out flag is allowed per command');
}

Type guard

function outArgCount(args: string[]): number {
  return args.filter(a => a === '--out' || a.startsWith('--out=')).length;
}

Try / catch

try {
  parseOutArgs(args);
} catch (e: any) {
  if (/--out specified more than once/.test(e.message)) {
    // keep only the first --out occurrence
    const deduped: string[] = [];
    let seen = false;
    for (let i = 0; i < args.length; i++) {
      if (args[i] === '--out' || args[i].startsWith('--out=')) {
        if (seen) continue;
        seen = true;
        if (args[i] === '--out') { deduped.push(args[i], args[i + 1]); i++; }
        else deduped.push(args[i]);
      } else deduped.push(args[i]);
    }
    parseOutArgs(deduped);
  } else throw e;
}

Prevention

When it happens

Trigger: Passing `browse js <expr> --out a.png --out b.png` — the second --out triggers the check because outPath is already set.

Common situations: Script or wrapper that appends --out automatically on top of a user-supplied --out; copy-paste duplication; shell alias that injects --out; arg array built by concatenation that double-adds the flag.

Related errors


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