anomalyco/sst · error · VisibleError

SSR server bundle not found in the build output at: "${pat

Error message

SSR server bundle not found in the build output at:
  "${path.resolve(distPath)}".

Expected either Astro v5 output in `dist/_worker.js/index.js` or Astro v6+ output in `dist/server/wrangler.json`.
If your Astro project is entirely pre-rendered, use the `sst.cloudflare.StaticSite` component instead of `sst.cloudflare.Astro`.

What it means

sst.cloudflare.Astro expects the Astro build to produce an SSR server bundle, but after running `astro build` no recognized server output was found at the configured dist path. SST supports Astro v5 layout (`dist/_worker.js/index.js`) and Astro v6+ layout (`dist/server/wrangler.json`). If the site is fully static (no SSR/on-demand routes), Astro produces no server bundle and the StaticSite component must be used instead.

Source

Thrown at platform/src/components/cloudflare/astro.ts:329

        const wrangler = JSON.parse(
          await fs.readFile(wranglerPath, "utf-8"),
        ) as WranglerConfig;
        const main = wrangler.main ?? "entry.mjs";
        const serverEntry = path.resolve(serverPath, main);
        const assetsDirectory = wrangler.assets?.directory;
        const assetsPath = assetsDirectory
          ? path.resolve(serverPath, assetsDirectory)
          : path.join(distPath, "client");

        if (await existsAsync(serverEntry)) {
          return {
            server: toRelativePath(serverEntry),
            assets: toRelativePath(assetsPath),
          };
        }
      }

      throw new VisibleError(
        `SSR server bundle not found in the build output at:\n` +
          `  "${path.resolve(distPath)}".\n\n` +
          `Expected either Astro v5 output in \`dist/_worker.js/index.js\` or Astro v6+ output in \`dist/server/wrangler.json\`.\n` +
          `If your Astro project is entirely pre-rendered, use the \`sst.cloudflare.StaticSite\` component instead of \`sst.cloudflare.Astro\`.`,
      );

      function toRelativePath(filePath: string) {
        const relative = path.relative(outputPath, filePath);
        return relative.startsWith(".") ? relative : `./${relative}`;
      }
    });
  }

  /**
   * The URL of the Astro site.
   *
   * If the `domain` is set, this is the URL with the custom domain.
   * Otherwise, it's the auto-generated Worker URL.

View on GitHub (pinned to a0bd20f762)

Solutions

  1. If the site is entirely pre-rendered, replace `sst.cloudflare.Astro` with `sst.cloudflare.StaticSite` in your sst.config.ts.
  2. If you need SSR, set `output: 'server'` (or use on-demand rendering) in astro.config.mjs and rebuild.
  3. Run the Astro build and confirm the expected bundle exists (`dist/_worker.js/index.js` for v5, `dist/server/wrangler.json` for v6+).
  4. Ensure the component's `path`/build output settings point at the directory Astro actually writes to.

Example fix

// before (sst.config.ts)
const site = new sst.cloudflare.Astro(ctx, "Site", {});
// after (for a fully static site)
const site = new sst.cloudflare.StaticSite(ctx, "Site", {
  path: "my-astro-app",
  build: { output: "dist" },
});
Defensive patterns

Strategy: validation

Validate before calling

import fs from "fs";
import path from "path";
const dist = "my-astro-app/dist";
const isV5 = fs.existsSync(path.join(dist, "_worker.js/index.js"));
const isV6 = fs.existsSync(path.join(dist, "server/wrangler.json"));
if (!isV5 && !isV6) console.warn("No SSR bundle: use sst.cloudflare.StaticSite or set output: 'server'");

Type guard

const hasSsrOutput = (dist: string) =>
  fs.existsSync(path.join(dist, "_worker.js/index.js")) ||
  fs.existsSync(path.join(dist, "server/wrangler.json"));

Try / catch

try {
  new sst.cloudflare.Astro(app, "Site", {});
} catch (e) {
  if (String(e).includes("SSR server bundle not found")) {
    // fall back to StaticSite or fix astro output config
  } else throw e;
}

Prevention

When it happens

Trigger: Running `sst deploy` (buildPlan in platform/src/components/cloudflare/astro.ts) after an Astro build where neither `dist/_worker.js/index.js` nor `dist/server/wrangler.json` exists — typically because `output: 'static'` is set in astro.config, or because the build never ran / ran into a different dist directory.

Common situations: Astro project configured as fully static but wrapped in sst.cloudflare.Astro; Astro build failed silently or was skipped; `dist` directory stale or cleaned; Astro version mismatch producing an unexpected output layout; custom `outDir` not matching what SST inspects.

Related errors


AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30). Data as JSON: /api/errors/801d9dff4c09e8c9. Report an issue: GitHub.