{"record":{"id":"4bb6abd18c900724","repo":"aaif-goose/goose","slug":"goose-serve-did-not-become-ready-on-statusurl","errorCode":null,"errorMessage":"goose serve did not become ready on ${statusUrl}.${exitDetails}${stderrDetails}","messagePattern":"goose serve did not become ready on (.+?)\\.(.+?)(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ui/desktop/src/gooseServe.ts","lineNumber":558,"sourceCode":"    healthUrl,\n    readinessFetch,\n    onEvent: startupTrace?.record,\n  });\n\n  const stopOutputCollection = () => {\n    stopStdoutCollection();\n    gooseProcess.stderr?.off('data', onStderrData);\n    gooseProcess.stderr?.resume();\n  };\n\n  if (!ready) {\n    stopOutputCollection();\n    await cleanup();\n    const exitDetails = exited\n      ? ` Process exited with code ${exitCode} and signal ${exitSignal}.`\n      : '';\n    const stderrDetails = errorLog.length ? ` Stderr: ${errorLog.join('\\n')}` : '';\n    throw new Error(\n      withStartupDiagnosticsPath(\n        `goose serve did not become ready on ${statusUrl}.${exitDetails}${stderrDetails}`,\n        startupDiagnosticsPath\n      )\n    );\n  }\n\n  if (tls) {\n    startupTrace?.record('fingerprint_wait_start', { timeoutMs: TLS_FINGERPRINT_TIMEOUT_MS });\n    const fingerprint = await waitForFingerprint(fingerprintReady, TLS_FINGERPRINT_TIMEOUT_MS);\n    if (!fingerprint) {\n      stopOutputCollection();\n      await cleanup();\n      const exitDetails = exited\n        ? ` Process exited with code ${exitCode} and signal ${exitSignal}.`\n        : '';\n      const stderrDetails = errorLog.length ? ` Stderr: ${errorLog.join('\\n')}` : '';\n      startupTrace?.record('fingerprint_missing', {","sourceCodeStart":540,"sourceCodeEnd":576,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/ui/desktop/src/gooseServe.ts#L540-L576","documentation":"startGooseServe spawns the goose binary with `goose serve`, then polls a status URL (HTTPS GET /status by default) until ready. If the process never reports ready within the startup timeout, this error is thrown after cleanup; the message includes the statusUrl, whether the process exited (code and signal), and any collected stderr, plus the diagnostics trace path. It means the backend either crashed, hung, or is listening somewhere other than the probed URL.","triggerScenarios":"goose serve exits immediately (bad flag, unsupported subcommand in an old binary, port conflict after findAvailablePort race); the /status endpoint never returns ok within the readiness timeout; the process hangs on startup due to broken config or a locked GOOSE_PATH_ROOT.","commonSituations":"Bundled goose binary is older than the desktop app and lacks `serve`; leftover goose serve processes holding ports; corporate proxy intercepting readinessFetch; first-run config migration stalling startup; TLS env vars set inconsistently so the server listens with plain HTTP while the probe uses HTTPS.","solutions":["Read the stderr text embedded in the message and the diagnostics file path appended to it — they usually name the real failure (e.g. 'unknown command serve', config parse error)","Run the same command manually to reproduce: `<goosePath> serve` with the env shown in diagnostics, and watch it exit","Kill stale goose processes and retry so findAvailablePort gets a clean port","If the binary is outdated, update it (or point the build at the correct bundled binary) so `serve` exists and matches the desktop app version"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Pre-flight the binary before starting:\nimport { access, constants } from 'fs/promises';\nawait access(goosePath, constants.X_OK); // throws early if binary missing","typeGuard":null,"tryCatchPattern":"try {\n  result = await startGooseServe(opts);\n} catch (e) {\n  const m = e instanceof Error ? e.message : '';\n  const diagPath = m.match(/diagnostics?:?\\s*(\\S+)/)?.[1];\n  // show m to user; open diagPath for full startup trace\n  throw e;\n}","preventionTips":["Always surface the embedded stderr and diagnostics path — they contain the true cause","In tests, wrap spawn with a fake readinessFetch you control to avoid real timeouts","Ensure bundled goose binary version matches the desktop app before shipping"],"tags":["process","startup","timeout","goose-serve","electron","readiness"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}