aaif-goose/goose · critical

GOOSE_SERVER__SECRET_KEY must be set when using GOOSE_EXTERN

Error message

GOOSE_SERVER__SECRET_KEY must be set when using GOOSE_EXTERNAL_BACKEND. Set it to the same value on both the server and the desktop client.

What it means

At startup, main.ts reads GOOSE_EXTERNAL_BACKEND to point the desktop at an externally-run goose server instead of spawning one. That protocol requires a shared auth secret, so if GOOSE_EXTERNAL_BACKEND is set but GOOSE_SERVER__SECRET_KEY is empty, getExternalBackendFromEnv throws this immediately — it refuses an unauthenticated connection to a remote backend.

Source

Thrown at ui/desktop/src/main.ts:929

  }

  const configuredUrl = process.env.GOOSE_EXTERNAL_BACKEND_URL?.trim();
  if (configuredUrl) {
    return configuredUrl;
  }

  return `http://127.0.0.1:${process.env.GOOSE_PORT || '3000'}`;
};

const getExternalBackendFromEnv = (): ExternalBackend | null => {
  const url = getExternalBackendUrlFromEnv();
  if (!url) {
    return null;
  }

  const secret = process.env.GOOSE_SERVER__SECRET_KEY;
  if (!secret) {
    throw new Error(
      'GOOSE_SERVER__SECRET_KEY must be set when using GOOSE_EXTERNAL_BACKEND. ' +
        'Set it to the same value on both the server and the desktop client.'
    );
  }

  return {
    source: 'env',
    url,
    secret,
  };
};

const getServerSecret = (settings: Settings): string => {
  if (settings.externalGoosed?.enabled && settings.externalGoosed.secret) {
    return settings.externalGoosed.secret;
  }
  return GENERATED_SECRET;
};

View on GitHub (pinned to 3810898a74)

Solutions

  1. Export GOOSE_SERVER__SECRET_KEY in the desktop client's environment with the exact same value the server was started with
  2. Double-check spelling and dunder: GOOSE_SERVER__SECRET_KEY (two underscores between SERVER and SECRET_KEY)
  3. If you did not intend an external backend, unset GOOSE_EXTERNAL_BACKEND so the app spawns its local backend and generates its own secret

Example fix

# before
export GOOSE_EXTERNAL_BACKEND=http://10.0.0.5:8000
open Goose.app  # throws
# after (same value the server used)
export GOOSE_SERVER__SECRET_KEY="$SECRET" 
export GOOSE_EXTERNAL_BACKEND=http://10.0.0.5:8000
open Goose.app
Defensive patterns

Strategy: validation

Validate before calling

// Run before app.whenReady():
const url = process.env.GOOSE_EXTERNAL_BACKEND;
if (url && !process.env.GOOSE_SERVER__SECRET_KEY) {
  throw new Error('GOOSE_EXTERNAL_BACKEND requires GOOSE_SERVER__SECRET_KEY');
}

Type guard

const hasExternalBackendConfig = (): boolean =>
  Boolean(process.env.GOOSE_EXTERNAL_BACKEND) &&
  Boolean(process.env.GOOSE_SERVER__SECRET_KEY && process.env.GOOSE_SERVER__SECRET_KEY.length > 0);

Try / catch

try {
  backend = getExternalBackendFromEnv();
} catch (e) {
  // config error: print the message and exit; do not fall back to local backend silently
  dialog.showErrorBox('Configuration error', e instanceof Error ? e.message : String(e));
  app.quit();
}

Prevention

When it happens

Trigger: Launching Goose Desktop with GOOSE_EXTERNAL_BACKEND=http://host:port but no GOOSE_SERVER__SECRET_KEY in the environment; secret set in the server's shell but not in the one launching Electron; typo in the variable name (e.g. GOOSE_SERVER_SECRET_KEY) so it reads undefined.

Common situations: Teams running goose serve centrally and connecting desktop clients; CI launching the app against a test backend; secret managed via dotenv file that isn't loaded because the app was started from Finder/Dock rather than a shell.

Related errors


AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16). Data as JSON: /api/errors/391549a8a0e2d622. Report an issue: GitHub.