garrytan/gstack · error · BrowseClientError
1
1
Error message
browse newtab exited 1: could not parse tab id from: ${out} What it means
BrowseClientError(1, 'newtab', ...) thrown when neither the --json path nor the legacy stdout regex `/tab\s+(\d+)/i` could extract a tab id from `browse newtab` output. The fallback exists for older browse builds that lack --json; if both fail the client cannot proceed because subsequent calls need a numeric tabId.
Source
Thrown at make-pdf/src/browseClient.ts:239
* Open a new tab. Returns the tabId.
* Requires `$B newtab --json` to be available (added in the browse flag
* extension for this feature). If --json isn't supported yet, the fallback
* parses "Opened tab N" from stdout.
*/
export function newtab(url?: string): number {
const args = ["newtab"];
if (url) args.push(url);
// Try --json first (preferred path for programmatic use)
try {
const out = runBrowse([...args, "--json"]);
const parsed = JSON.parse(out);
if (typeof parsed.tabId === "number") return parsed.tabId;
} catch {
// Fall back to stdout-string parsing. Brittle, but works on older browse builds.
}
const out = runBrowse(args);
const m = out.match(/tab\s+(\d+)/i);
if (!m) throw new BrowseClientError(1, "newtab", `could not parse tab id from: ${out}`);
return parseInt(m[1], 10);
}
/**
* Close a tab (by id or the active tab).
*/
export function closetab(tabId?: number): void {
const args = ["closetab"];
if (tabId !== undefined) args.push(String(tabId));
runBrowse(args);
}
/**
* Load raw HTML into a specific tab.
* Uses --from-file for any payload >4KB (Codex round 2 #3).
*/
export function loadHtml(opts: LoadHtmlOptions): void {
// Always use --from-file to dodge argv limits. The HTML is almost always >4KB.View on GitHub (pinned to 94993f7401)
Solutions
- Upgrade browse to a build that supports `newtab --json` (the preferred path).
- Run `browse newtab --json` manually and inspect the output to confirm tabId is present.
- If --json works but returns a different key, update the parser in newtab().
- Restart the browse daemon to clear the bad-state stdout.
Example fix
// before
const out = runBrowse(args);
const m = out.match(/tab\s+(\d+)/i);
if (!m) throw new BrowseClientError(1, 'newtab', `could not parse tab id from: ${out}`);
return parseInt(m[1], 10);
// after: prefer --json strictly, broaden fallback regex, log raw output on failure
try {
const parsed = JSON.parse(runBrowse([...args, '--json']));
if (typeof parsed.tabId === 'number') return parsed.tabId;
if (typeof parsed.id === 'number') return parsed.id; // alternate key
} catch { /* legacy */ }
const out = runBrowse(args);
const m = out.match(/tab\s*(?:id)?[:\s]*(\d+)/i);
if (!m) throw new BrowseClientError(1, 'newtab', `could not parse tab id from: ${JSON.stringify(out)}`);
return parseInt(m[1], 10); Defensive patterns
Strategy: validation
Validate before calling
// Probe browse capabilities once and pick the newtab strategy.
function supportsNewtabJson(): boolean {
try {
const out = runBrowse(['newtab', '--help']);
return /--json/.test(out);
} catch {
return false;
}
}
const useJson = supportsNewtabJson(); Try / catch
try {
return newtab(url);
} catch (e) {
if (e instanceof BrowseClientError && e.command === 'newtab' && /could not parse/i.test(e.message)) {
// upgrade prompt: this browse build is too old
throw new Error('browse build too old for newtab — re-run ./setup');
}
throw e;
} Prevention
- Use a browse build that supports `newtab --json`.
- Restart the daemon if newtab output starts including diagnostic banners.
- Pin browse to a known-good version in CI.
- Do not localize the browse CLI output (keep C/POSIX locale).
When it happens
Trigger: Calling newtab(url) where browse is too old to support --json AND its stdout text changed format (e.g. localized output, a new banner line, or a version that prints 'tab id: 7' instead of 'tab 7'). Also when browse exits 0 but prints an error notice to stdout instead of opening a tab.
Common situations: A browse build from a different branch that changed the newtab CLI output; non-English locale altering the word 'tab'; a daemon in a bad state that prints a diagnostic to stdout but returns 0; a stdin/stdout capture that strips the relevant line.
Related errors
- 127
- browse ${args[0] || "unknown"} exited ${exitCode}: ${stderr}
- diagram-render bundle did not become ready in the browse tab
- Usage: browse tab <id>
- Usage: browse tab-each <command> [args...] Example: browse t
AI-assisted analysis of garrytan/gstack@94993f7401 (2026-08-12).
Data as JSON: /api/errors/a971f8bd7b2bbf14.
Report an issue: GitHub.