{"record":{"id":"f0145d7f588efc44","repo":"aaif-goose/goose","slug":"goose-server-secret-key-is-required-for-goose-ser","errorCode":null,"errorMessage":"GOOSE_SERVER__SECRET_KEY is required for goose serve","messagePattern":"GOOSE_SERVER__SECRET_KEY is required for goose serve","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"ui/desktop/src/gooseServe.ts","lineNumber":344,"sourceCode":"  dir,\n  serverSecret,\n  tls = false,\n  env: additionalEnv = {},\n  loginShellPath,\n  isPackaged,\n  resourcesPath,\n  logger = defaultLogger,\n  diagnosticsDir,\n  readinessFetch = fetch,\n}: StartGooseServeOptions): Promise<GooseServeResult> => {\n  const workingDir = dir || process.cwd();\n  const startupTrace = createGooseServeStartupDiagnostics(diagnosticsDir, workingDir);\n  const startupDiagnosticsPath = startupTrace?.diagnosticsPath ?? null;\n  const secretKey = serverSecret.trim();\n  if (!secretKey) {\n    const message = 'GOOSE_SERVER__SECRET_KEY is required for goose serve';\n    startupTrace?.record('configuration_error', { message });\n    throw new Error(withStartupDiagnosticsPath(message, startupDiagnosticsPath));\n  }\n\n  let goosePath: string;\n  try {\n    goosePath = findGooseBinaryPath({ isPackaged, resourcesPath });\n  } catch (error) {\n    const message = errorMessage(error);\n    startupTrace?.record('binary_resolve_error', { message });\n    throw new Error(withStartupDiagnosticsPath(message, startupDiagnosticsPath));\n  }\n\n  const port = await findAvailablePort();\n  const localServeScheme: LocalServeScheme = tls ? 'https' : 'http';\n  const { httpBaseUrl, statusUrl, healthUrl, acpUrl, redactedAcpUrl } = buildLocalServeUrls(\n    port,\n    secretKey,\n    localServeScheme\n  );","sourceCodeStart":326,"sourceCodeEnd":362,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/ui/desktop/src/gooseServe.ts#L326-L362","documentation":"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.","triggerScenarios":"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.","commonSituations":"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 '').","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"],"exampleFix":"// before\nawait startGooseServe({ serverSecret: process.env.GOOSE_SERVER__SECRET_KEY ?? '' });\n// after\nimport { randomBytes } from 'crypto';\nconst secret = process.env.GOOSE_SERVER__SECRET_KEY || randomBytes(32).toString('hex');\nawait startGooseServe({ serverSecret: secret });","handlingStrategy":"validation","validationCode":"import { randomBytes } from 'crypto';\nconst secret = process.env.GOOSE_SERVER__SECRET_KEY?.trim() || randomBytes(32).toString('hex');\nif (!secret) throw new Error('bug: secret generation failed');\n// safe to call:\nawait startGooseServe({ serverSecret: secret, /* ... */ });","typeGuard":"const hasServerSecret = (opts: StartGooseServeOptions): boolean =>\n  typeof opts.serverSecret === 'string' && opts.serverSecret.trim().length > 0;","tryCatchPattern":"try {\n  await startGooseServe({ serverSecret: secret });\n} catch (e) {\n  if (e instanceof Error && e.message.includes('GOOSE_SERVER__SECRET_KEY')) {\n    // config problem: fix secret source, not a transient failure — do not retry blindly\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["config","secrets","goose-serve","electron","startup"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}