{"record":{"id":"f9194def8eedc88c","repo":"TryGhost/Ghost","slug":"ghost-container-became-unhealthy-during-initializa","errorCode":null,"errorMessage":"Ghost container became unhealthy during initialization","messagePattern":"Ghost container became unhealthy during initialization","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"e2e/helpers/environment/service-managers/ghost-manager.ts","lineNumber":504,"sourceCode":"    }\n\n    private async waitForHostReadiness(container: Container, timeoutMs: number): Promise<void> {\n        const startTime = Date.now();\n\n        while (Date.now() - startTime < timeoutMs) {\n            const info = await container.inspect();\n            const health = info.State.Health;\n            const status = health?.Status;\n\n            if (info.State.Running && await this.probeHostReadiness()) {\n                debug('Host readiness probe passed');\n                return;\n            }\n\n            if (status === 'unhealthy') {\n                const logs = await container.logs({stdout: true, stderr: true, tail: 100});\n                logging.error(`Container became unhealthy:\\n${logs.toString()}`);\n                throw new Error('Ghost container became unhealthy during initialization');\n            }\n\n            if (!info.State.Running) {\n                const logs = await container.logs({stdout: true, stderr: true, tail: 100});\n                logging.error(`Container stopped unexpectedly:\\n${logs.toString()}`);\n                throw new Error('Ghost container stopped during initialization');\n            }\n\n            // Still starting - wait and check again\n            await new Promise((r) => {\n                setTimeout(r, READINESS_POLL_INTERVAL_MS);\n            });\n        }\n\n        // Timeout\n        const logs = await container.logs({stdout: true, stderr: true, tail: 100});\n        logging.error(`Timeout waiting for container. Last logs:\\n${logs.toString()}`);\n        throw new Error('Timeout waiting for Ghost to become ready');","sourceCodeStart":486,"sourceCodeEnd":522,"githubUrl":"https://github.com/TryGhost/Ghost/blob/47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe/e2e/helpers/environment/service-managers/ghost-manager.ts#L486-L522","documentation":"During the readiness loop, the container's State.Health.Status is 'unhealthy' — Docker's HEALTHCHECK (defined in the Ghost image) marked the container failing. The manager dumps the last 100 log lines at error level and aborts initialization. This is a real Ghost-side failure: the process is running but the health probe (typically an HTTP check against /ghost/api/) is failing.","triggerScenarios":"Ghost started but crashed during bootstrap (DB migration failure, bad config, missing env var, port conflict). The image's HEALTHCHECK endpoint is unreachable because Ghost errored on boot. A corrupt database or invalid url/config caused the admin API to never come up.","commonSituations":"Wrong database__connection__database pointing at a missing/corrupt DB; invalid url env (not http://localhost:port); a Ghost start-up exception (visible in the dumped logs); incompatible Ghost version vs config; port already bound by another container.","solutions":["Read the dumped container logs (last 100 lines) — the actual Ghost bootstrap error is there.","Verify the database name and MySQL container are reachable from Ghost; check database__connection__* env values.","Confirm the url env matches the gateway port and uses http://localhost:<getGatewayPort()>.","Rebuild/re-pull the Ghost image if a code/config change broke boot; check for migration errors in logs."],"exampleFix":"# before (opaque failure)\n# Error: Ghost container became unhealthy during initialization\n\n# after\n# Capture and surface logs proactively:\ndocker logs <ghost-container> --tail 200\n# Then fix the root cause shown (e.g. bad DB name, bad url env).","handlingStrategy":"try-catch","validationCode":"// Before relying on the container, pre-flight the health:\nconst info = await container.inspect();\nif (info.State.Health?.Status === 'unhealthy') {\n    const logs = (await container.logs({stdout:true, stderr:true, tail: 100})).toString('utf8');\n    throw new Error(`Refusing to start — Ghost unhealthy pre-check:\\n${logs}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n    await ghostManager.waitForReady();\n} catch (e) {\n    const logs = (await container.logs({stdout:true, stderr:true, tail: 200})).toString('utf8');\n    throw new Error(`Ghost readiness failed; logs:\\n${logs}`, {cause: e});\n}","preventionTips":["Always surface the dumped container logs when this fires — the real bootstrap error is there.","Validate database name, url env, and DB reachability before starting Ghost.","Use a migrated seed image to avoid migration-time bootstrap failures."],"tags":["e2e","docker","healthcheck","ghost-startup","logging"],"backgroundTag":null,"analyzedSha":"47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe","analyzedAt":"2026-08-13T01:25:26.651Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}