{"record":{"id":"7ac7ca00d2220124","repo":"TryGhost/Ghost","slug":"build-gateway-image-not-found-build-gateway-ima","errorCode":null,"errorMessage":"Build gateway image not found: ${BUILD_GATEWAY_IMAGE}\\n\\nTo fix this, either:\\n  1. Pull gateway image: docker pull ${BUILD_GATEWAY_IMAGE}\\n  2. Use a different gateway image: GHOST_E2E_MODE=build GHOST_E2E_GATEWAY_IMAGE=<image> pnpm --filter @tryghost/e2e test","messagePattern":"Build gateway image not found: (.+?)\\\\n\\\\nTo fix this, either:\\\\n  1\\. Pull gateway image: docker pull (.+?)\\\\n  2\\. Use a different gateway image: GHOST_E2E_MODE=build GHOST_E2E_GATEWAY_IMAGE=<image> pnpm --filter @tryghost/e2e test","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"e2e/helpers/environment/service-managers/ghost-manager.ts","lineNumber":144,"sourceCode":"        } catch {\n            throw new Error(\n                `Build image not found: ${BUILD_IMAGE}\\n\\n` +\n                `You are running in \"build\" mode, which requires a pre-built Docker image.\\n` +\n                `For local development, \"dev\" mode is recommended instead.\\n\\n` +\n                `To fix this, either:\\n` +\n                `  1. (Recommended) Run \"pnpm dev\" first, then re-run tests — dev mode is auto-detected and doesn't need this image\\n` +\n                `  2. Build locally: pnpm --filter @tryghost/e2e build:docker (with GHOST_E2E_BASE_IMAGE set)\\n` +\n                `  3. Pull from registry: docker pull ${BUILD_IMAGE}\\n` +\n                `  4. Use a different image: GHOST_E2E_MODE=build GHOST_E2E_IMAGE=<image> pnpm --filter @tryghost/e2e test`\n            );\n        }\n\n        try {\n            const gatewayImage = this.docker.getImage(BUILD_GATEWAY_IMAGE);\n            await gatewayImage.inspect();\n            debug(`Build gateway image verified: ${BUILD_GATEWAY_IMAGE}`);\n        } catch {\n            throw new Error(\n                `Build gateway image not found: ${BUILD_GATEWAY_IMAGE}\\n\\n` +\n                `To fix this, either:\\n` +\n                `  1. Pull gateway image: docker pull ${BUILD_GATEWAY_IMAGE}\\n` +\n                `  2. Use a different gateway image: GHOST_E2E_MODE=build GHOST_E2E_GATEWAY_IMAGE=<image> pnpm --filter @tryghost/e2e test`\n            );\n        }\n\n        GhostManager.verifiedBuildImageKey = buildImageKey;\n    }\n\n    /**\n     * Get existing container if running, otherwise create new one.\n     * This handles Playwright respawning processes after test failures.\n     */\n    private async getOrCreateContainer(name: string, create: () => Promise<Container>): Promise<Container> {\n        try {\n            const existing = this.docker.getContainer(name);\n            const info = await existing.inspect();","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/TryGhost/Ghost/blob/47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe/e2e/helpers/environment/service-managers/ghost-manager.ts#L126-L162","documentation":"Companion to error 101: after the main Ghost build image is verified, verifyBuildImageExists() separately inspects BUILD_GATEWAY_IMAGE (the traffic-routing gateway container image, e.g. nginx/traefik fronting Ghost). Inspect rejection throws with gateway-specific remediation. Only fires in build mode. Shares the same verifiedBuildImageKey cache, so it runs once per process per image pair.","triggerScenarios":"BUILD_GATEWAY_IMAGE (from GHOST_E2E_GATEWAY_IMAGE) is absent locally. The main image exists but the gateway image was never pulled/built. Gateway tag was changed via env without re-pulling. Different registry/source than the Ghost image so a single pull doesn't cover both.","commonSituations":"Hardened CI that caches the Ghost image but not the gateway image; switching gateway variants; new contributor running build mode who only pulled the Ghost image.","solutions":["Pull the gateway image: docker pull ${BUILD_GATEWAY_IMAGE}.","Point at a different gateway image: GHOST_E2E_MODE=build GHOST_E2E_GATEWAY_IMAGE=<image> pnpm --filter @tryghost/e2e test.","Confirm the tag matches what the build pipeline pushes; add the gateway image to CI's docker-pull step alongside BUILD_IMAGE."],"exampleFix":"# before\nGHOST_E2E_MODE=build pnpm --filter @tryghost/e2e test\n\n# after\ndocker pull ${BUILD_GATEWAY_IMAGE} && GHOST_E2E_MODE=build pnpm --filter @tryghost/e2e test","handlingStrategy":"validation","validationCode":"async function gatewayImageExists(): Promise<boolean> {\n    try { await new Docker().getImage(BUILD_GATEWAY_IMAGE).inspect(); return true; }\n    catch { return false; }\n}\nif (GHOST_E2E_MODE === 'build' && !await gatewayImageExists()) {\n    throw new Error(`Pre-flight: gateway image ${BUILD_GATEWAY_IMAGE} missing. docker pull it.`);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pull the gateway image alongside the Ghost image in CI's setup step.","Document GHOST_E2E_GATEWAY_IMAGE in the env docs so contributors set both.","Cache both images in CI to avoid repeated registry pulls."],"tags":["docker","e2e","build-mode","gateway","configuration"],"backgroundTag":null,"analyzedSha":"47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe","analyzedAt":"2026-08-13T01:25:26.651Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}