anomalyco/sst · error · VisibleError

React Router assets directory not found at: "${assetsPath}

Error message

React Router assets directory not found at:
  "${assetsPath}".

What it means

SST expects the client assets at `build/client` in the React Router output directory. When that directory is absent the Worker plan can't reference static assets, so SST throws a VisibleError. This usually means the build didn't complete as expected or the path is wrong.

Source

Thrown at platform/src/components/cloudflare/react-router.ts:291

  protected buildPlan(outputPath: Output<string>): Output<Plan> {
    return outputPath.apply(async (outputPath) => {
      const serverPath = path.join(outputPath, "build", "server", "index.js");
      const assetsPath = path.join(outputPath, "build", "client");

      if (!(await existsAsync(serverPath))) {
        throw new VisibleError(
          [
            `React Router server bundle not found at:\n  "${serverPath}".`,
            "",
            "Make sure the Cloudflare Vite plugin is configured in your `vite.config.ts`.",
            "If your React Router project is entirely pre-rendered, use `sst.cloudflare.StaticSite` instead.",
          ].join("\n"),
        );
      }

      if (!(await existsAsync(assetsPath))) {
        throw new VisibleError(
          `React Router assets directory not found at:\n  "${assetsPath}".`,
        );
      }

      return {
        server: "./build/server/index.js",
        assets: "./build/client",
      };
    });
  }

  protected buildWrangler(sitePath: string) {
    return {
      main: path.resolve(sitePath, "workers/app.ts"),
    };
  }

  /**

View on GitHub (pinned to a0bd20f762)

Solutions

  1. Run the full project build and confirm `build/client` exists before deploying
  2. Fix the component's `path` to the directory containing the `build/` output
  3. Restore the default Vite outDir or configure the build so client assets land in `build/client`

Example fix

// before
new sst.cloudflare.ReactRouter('Site', { path: 'apps/web/dist' }); // dist has no build/client
// after
new sst.cloudflare.ReactRouter('Site', { path: 'apps/web' }); // build client+server present after `vite build`
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync } from 'fs';
if (!existsSync('apps/web/build/client'))
  throw new Error('Run the full vite build first: build/client is required');
new sst.cloudflare.ReactRouter('Site', { path: 'apps/web' });

Try / catch

try {
  await deploy();
} catch (e) {
  if (/assets directory not found/.test(e.message)) console.error('Client build output missing; run full build');
}

Prevention

When it happens

Trigger: `sst deploy` on a React Router project where `build/client` does not exist: partial/failed build, custom outDir changed in vite config, or component `path` pointing at the wrong directory.

Common situations: Build interrupted leaving only `build/server`; moving the client outDir via Vite config without updating SST config; deploying from CI where the build step was skipped or ran in a different directory.

Related errors


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