garrytan/gstack · error · Error

buildFetchHandler: cfg.authToken must be a non-empty string

Error message

buildFetchHandler: cfg.authToken must be a non-empty string >= 16 chars

What it means

Error "buildFetchHandler: cfg.authToken must be a non-empty string >= 16 chars" thrown in garrytan/gstack.

Source

Thrown at browse/src/server.ts:1471

 * routes via cfg.beforeRoute, pass a pre-launched cfg.browserManager, and
 * opt out of terminal-agent teardown via cfg.ownsTerminalAgent (default
 * true, set to false when the embedder runs its own PTY server). The CLI
 * path calls this through start() with env-derived defaults and explicit
 * cfg.ownsTerminalAgent: true — externally-observable behavior is identical.
 *
 * Auth state lives ENTIRELY inside the factory closure: cfg.authToken is the
 * single source of truth for the bearer secret, factory-scoped validateAuth
 * closes over it, and factory-scoped shutdown closes the cfg-provided
 * browserManager. Module-level lifecycle singletons (LOCAL_LISTEN_PORT,
 * tunnelActive, inspector state) intentionally STAY at module scope; see
 * the v1.35.0.0 CHANGELOG entry for the architectural rationale.
 *
 * The returned ServerHandle is callable directly. Bun.serve is the caller's
 * responsibility — embedders may fd-pass; CLI uses Bun.serve normally.
 */
export function buildFetchHandler(cfg: ServerConfig): ServerHandle {
  if (!cfg.authToken || cfg.authToken.length < 16) {
    throw new Error('buildFetchHandler: cfg.authToken must be a non-empty string >= 16 chars');
  }
  if (!cfg.browserManager) {
    throw new Error('buildFetchHandler: cfg.browserManager is required');
  }

  // Re-run init with cfg-provided values. ensureStateDir is idempotent
  // (mkdir -p); initAuditLog is idempotent (sets a module string);
  // initRegistry is idempotent for same-token, throws for different-token.
  // Owning init here (instead of at module load) means cfg.authToken is the
  // single source of truth for the registry root token.
  ensureStateDir(cfg.config);
  initAuditLog(cfg.config.auditLog);
  initRegistry(cfg.authToken);

  const { authToken, browserManager: cfgBrowserManager, startTime, beforeRoute, browsePort } = cfg;
  // Strict opt-out: only explicit `false` flips the gate. Any other value
  // (undefined, truthy non-bool from a JS caller bypassing TS, etc.) defaults
  // to gstack-owns. Matches the "default-true preserves CLI bit-for-bit"

View on GitHub (pinned to 94993f7401)

When it happens

Trigger: Thrown at browse/src/server.ts:1471 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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