aaif-goose/goose · critical
GOOSE_SERVER__SECRET_KEY is required for goose serve
Error message
GOOSE_SERVER__SECRET_KEY is required for goose serve
What it means
Thrown by startGooseServe in the Electron main process when the serverSecret argument is empty after trimming. goose serve requires a shared bearer secret (GOOSE_SERVER__SECRET_KEY) to authenticate desktop<->backend traffic, so startup is aborted before the binary is even resolved. The error message is annotated with the path of a startup diagnostics trace that recorded a 'configuration_error' event.
Source
Thrown at ui/desktop/src/gooseServe.ts:344
dir,
serverSecret,
tls = false,
env: additionalEnv = {},
loginShellPath,
isPackaged,
resourcesPath,
logger = defaultLogger,
diagnosticsDir,
readinessFetch = fetch,
}: StartGooseServeOptions): Promise<GooseServeResult> => {
const workingDir = dir || process.cwd();
const startupTrace = createGooseServeStartupDiagnostics(diagnosticsDir, workingDir);
const startupDiagnosticsPath = startupTrace?.diagnosticsPath ?? null;
const secretKey = serverSecret.trim();
if (!secretKey) {
const message = 'GOOSE_SERVER__SECRET_KEY is required for goose serve';
startupTrace?.record('configuration_error', { message });
throw new Error(withStartupDiagnosticsPath(message, startupDiagnosticsPath));
}
let goosePath: string;
try {
goosePath = findGooseBinaryPath({ isPackaged, resourcesPath });
} catch (error) {
const message = errorMessage(error);
startupTrace?.record('binary_resolve_error', { message });
throw new Error(withStartupDiagnosticsPath(message, startupDiagnosticsPath));
}
const port = await findAvailablePort();
const localServeScheme: LocalServeScheme = tls ? 'https' : 'http';
const { httpBaseUrl, statusUrl, healthUrl, acpUrl, redactedAcpUrl } = buildLocalServeUrls(
port,
secretKey,
localServeScheme
);View on GitHub (pinned to 3810898a74)
Solutions
- Pass a non-empty secret, e.g. generate one with crypto.randomBytes(32).toString('hex) before calling startGooseServe
- If you meant to reuse an external server's secret, export GOOSE_SERVER__SECRET_KEY in both processes and read it before the call
- Open the startup diagnostics file whose path is appended to the message to confirm the 'configuration_error' entry and inspect the other recorded steps
Example fix
// before
await startGooseServe({ serverSecret: process.env.GOOSE_SERVER__SECRET_KEY ?? '' });
// after
import { randomBytes } from 'crypto';
const secret = process.env.GOOSE_SERVER__SECRET_KEY || randomBytes(32).toString('hex');
await startGooseServe({ serverSecret: secret }); Defensive patterns
Strategy: validation
Validate before calling
import { randomBytes } from 'crypto';
const secret = process.env.GOOSE_SERVER__SECRET_KEY?.trim() || randomBytes(32).toString('hex');
if (!secret) throw new Error('bug: secret generation failed');
// safe to call:
await startGooseServe({ serverSecret: secret, /* ... */ }); Type guard
const hasServerSecret = (opts: StartGooseServeOptions): boolean => typeof opts.serverSecret === 'string' && opts.serverSecret.trim().length > 0;
Try / catch
try {
await startGooseServe({ serverSecret: secret });
} catch (e) {
if (e instanceof Error && e.message.includes('GOOSE_SERVER__SECRET_KEY')) {
// config problem: fix secret source, not a transient failure — do not retry blindly
}
throw e;
} Prevention
- Generate the secret in exactly one place and pass it down; never read env at multiple layers
- Add a unit test asserting startGooseServe rejects empty/whitespace secrets with the diagnostics path attached
- Fail fast at process start: validate required env before any window opens
When it happens
Trigger: Calling startGooseServe({ serverSecret: '' }) or with a whitespace-only string; main.ts normally generates the secret, so this fires when a custom caller, test harness, or external-backend wiring passes an unset/empty value.
Common situations: Integrating gooseServe.ts into another entrypoint and forgetting to generate the secret; copying the external-backend flow but reading process.env.GOOSE_SERVER__SECRET_KEY before it is set; refactoring that renames the option and passes undefined (which then defaults to '').
Related errors
- goose serve did not become ready on ${statusUrl}.${exitDetai
- GOOSE_SERVER__SECRET_KEY must be set when using GOOSE_EXTERN
- ACP URL is not available
- goose serve did not emit TLS certificate fingerprint on ${st
- This window's Goose backend stopped. Close this window and o
AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16).
Data as JSON: /api/errors/f0145d7f588efc44.
Report an issue: GitHub.