aaif-goose/goose · error
goose serve TLS certificate fingerprint did not match readin
Error message
goose serve TLS certificate fingerprint did not match readiness probe
What it means
main.ts pins the server certificate: it keeps the fingerprint observed during the readiness probe (localCertificateTrust.trust.fingerprint) and compares it with the fingerprint goose serve itself reported. A mismatch means the endpoint's TLS identity changed between probe and serve — possible cert regeneration race, stale trust record from a previous run, or something else terminating TLS. The serve process is cleaned up and startup aborts with the 'goose serve failed to start' dialog.
Source
Thrown at ui/desktop/src/main.ts:1232
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',
title: 'Goose Failed to Start',
message: 'The backend server failed to start.',
detail: [
'Backend: goose serve',
'Readiness check: HTTPS GET /status',
`Startup error:\n${errorMessage(error)}`,
].join('\n\n'),
buttons: ['OK'],
});
app.quit();
return;View on GitHub (pinned to 3810898a74)
Solutions
- Restart the app so the trust record is refreshed with the new cert, and clear any persisted stale fingerprint if it persists across restarts
- Verify only one goose serve is running and the probe and serve hit the same process/port
- Disable TLS interception (proxies, corporate middleboxes) for 127.0.0.1 backend traffic
- Keep desktop and goose binary versions in lockstep so cert generation/pinning logic matches
Defensive patterns
Strategy: try-catch
Try / catch
try {
await startServeWithTrust();
} catch (e) {
if (e instanceof Error && e.message.includes('fingerprint did not match')) {
// clear persisted trust state and prompt restart; a retry with stale pinning will fail again
}
throw e;
} Prevention
- Invalidate persisted fingerprint trust whenever the server cert source is regenerated
- Ensure probe and serve use the same port/process — never reuse ports across restarts
- Exclude loopback backend traffic from TLS-inspecting proxies
When it happens
Trigger: A cached trust fingerprint from an earlier session while the server regenerated its self-signed cert this run; port reuse where a different process answered the probe; proxy/MITM terminating TLS so probe and serve present different certs; clock/entropy issues causing new certs per start with stale pinning state.
Common situations: Restarting Goose Desktop after the server cert file was deleted/regenerated; tests that run multiple serve instances against shared state; corporate TLS inspection inserting its own cert on one of the two paths.
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 started with TLS but did not return a certificat
- 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/793bfba088d8c788.
Report an issue: GitHub.