TryGhost/Ghost · critical · Error

Ghost container became unhealthy during initialization

Error message

Ghost container became unhealthy during initialization

What it means

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.

Source

Thrown at e2e/helpers/environment/service-managers/ghost-manager.ts:504

    }

    private async waitForHostReadiness(container: Container, timeoutMs: number): Promise<void> {
        const startTime = Date.now();

        while (Date.now() - startTime < timeoutMs) {
            const info = await container.inspect();
            const health = info.State.Health;
            const status = health?.Status;

            if (info.State.Running && await this.probeHostReadiness()) {
                debug('Host readiness probe passed');
                return;
            }

            if (status === 'unhealthy') {
                const logs = await container.logs({stdout: true, stderr: true, tail: 100});
                logging.error(`Container became unhealthy:\n${logs.toString()}`);
                throw new Error('Ghost container became unhealthy during initialization');
            }

            if (!info.State.Running) {
                const logs = await container.logs({stdout: true, stderr: true, tail: 100});
                logging.error(`Container stopped unexpectedly:\n${logs.toString()}`);
                throw new Error('Ghost container stopped during initialization');
            }

            // Still starting - wait and check again
            await new Promise((r) => {
                setTimeout(r, READINESS_POLL_INTERVAL_MS);
            });
        }

        // Timeout
        const logs = await container.logs({stdout: true, stderr: true, tail: 100});
        logging.error(`Timeout waiting for container. Last logs:\n${logs.toString()}`);
        throw new Error('Timeout waiting for Ghost to become ready');

View on GitHub (pinned to 47d8b0e2ad)

Solutions

  1. Read the dumped container logs (last 100 lines) — the actual Ghost bootstrap error is there.
  2. Verify the database name and MySQL container are reachable from Ghost; check database__connection__* env values.
  3. Confirm the url env matches the gateway port and uses http://localhost:<getGatewayPort()>.
  4. Rebuild/re-pull the Ghost image if a code/config change broke boot; check for migration errors in logs.

Example fix

# before (opaque failure)
# Error: Ghost container became unhealthy during initialization

# after
# Capture and surface logs proactively:
docker logs <ghost-container> --tail 200
# Then fix the root cause shown (e.g. bad DB name, bad url env).
Defensive patterns

Strategy: try-catch

Validate before calling

// Before relying on the container, pre-flight the health:
const info = await container.inspect();
if (info.State.Health?.Status === 'unhealthy') {
    const logs = (await container.logs({stdout:true, stderr:true, tail: 100})).toString('utf8');
    throw new Error(`Refusing to start — Ghost unhealthy pre-check:\n${logs}`);
}

Try / catch

try {
    await ghostManager.waitForReady();
} catch (e) {
    const logs = (await container.logs({stdout:true, stderr:true, tail: 200})).toString('utf8');
    throw new Error(`Ghost readiness failed; logs:\n${logs}`, {cause: e});
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of TryGhost/Ghost@47d8b0e2ad (2026-08-13). Data as JSON: /api/errors/f9194def8eedc88c. Report an issue: GitHub.