aaif-goose/goose · error
goose serve started with TLS but did not return a certificat
Error message
goose serve started with TLS but did not return a certificate fingerprint
What it means
After startGooseServe succeeds with TLS enabled, main.ts expects the result to carry certFingerprint (the serve process's self-signed cert pin). A missing fingerprint despite a TLS-enabled start means the version/format contract between the readiness probe (which captured a fingerprint) and the serve result diverged — the process is killed via cleanup() and app startup fails with a dialog.
Source
Thrown at ui/desktop/src/main.ts:1221
let gooseServeResult: Awaited<ReturnType<typeof startGooseServe>>;
try {
gooseServeResult = await startGooseServe({
serverSecret,
dir: workingDir,
tls: true,
env: {
GOOSE_PATH_ROOT: appConfig.GOOSE_PATH_ROOT as string | undefined,
},
loginShellPath,
isPackaged: app.isPackaged,
resourcesPath: app.isPackaged ? process.resourcesPath : undefined,
logger: log,
diagnosticsDir: STARTUP_LOGS_DIR,
readinessFetch: net.fetch as unknown as typeof globalThis.fetch,
});
if (!gooseServeResult.certFingerprint) {
await gooseServeResult.cleanup();
throw new Error(
'goose serve started with TLS but did not return a certificate fingerprint'
);
}
const localCertFingerprint = normalizeFingerprint(gooseServeResult.certFingerprint);
if (
localCertificateTrust.trust.fingerprint &&
localCertificateTrust.trust.fingerprint !== localCertFingerprint
) {
await gooseServeResult.cleanup();
throw new Error('goose serve TLS certificate fingerprint did not match readiness probe');
}
localCertificateTrust.trust.fingerprint = localCertFingerprint;
} catch (error) {
localCertificateTrust.release();
log.error('goose serve failed to start', error);
dialog.showMessageBoxSync({
type: 'error',View on GitHub (pinned to 3810898a74)
Solutions
- Update the goose binary so its TLS fingerprint output matches the desktop app's parser (keep binary and app versions in lockstep)
- If GOOSE_BINARY is set in dev, unset it or rebuild it from the same checkout
- Check the startup diagnostics trace for fingerprint_wait events to see whether waitForFingerprint timed out vs never started
- As a workaround, run without TLS locally so the fingerprint contract is skipped
Defensive patterns
Strategy: try-catch
Try / catch
// main.ts already wraps this in try/catch with cleanup + dialog; callers should let it
// propagate and rely on that handler:
try {
await startGooseServeFlow();
} catch (e) {
if (e instanceof Error && e.message.includes('did not return a certificate fingerprint')) {
// binary/app version skew: update goose, don't retry loop
}
throw e;
} Prevention
- Ship binary and desktop app as one versioned unit; reject mismatched pairs at startup
- In dev, rebuild the goose binary whenever gooseServe.ts parsing changes
- Assert certFingerprint presence in a smoke test for every release artifact
When it happens
Trigger: goose binary emits the fingerprint on a channel gooseServe.ts no longer parses (or vice versa after a downgrade); TLS handshake succeeded but fingerprint extraction from stdout/file returned nothing; mixed old binary + new desktop build.
Common situations: Partial updates where the desktop app updates but the bundled/native goose binary stays old (or GOOSE_BINARY points at a stale build); dev running against a locally built goose with changed output format; snapshot tests with a fake readinessFetch that never returns a fingerprint.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- goose serve did not emit TLS certificate fingerprint on ${st
- goose serve TLS certificate fingerprint did not match readin
- GOOSE_SERVER__SECRET_KEY is required for goose serve
- goose serve did not become ready on ${statusUrl}.${exitDetai
- ACP URL is not available
AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16).
Data as JSON: /api/errors/aac8afe09fc9ce16.
Report an issue: GitHub.