anomalyco/sst · error · VisibleError

TanStack Start assets directory not found at: "${path.reso

Error message

TanStack Start assets directory not found at:
  "${path.resolve(assetsPath)}".

What it means

SST falls back to the legacy TanStack Start (Nitro) layout: `.output/server/index.mjs` plus `.output/public`. In this fallback, if the server bundle exists but `.output/public` does not, SST throws because the legacy layout is only partially present.

Source

Thrown at platform/src/components/cloudflare/tan-stack-start.ts:369

              server: toPlanPath(serverPath),
              assets: toPlanPath(assetsPath),
            };
          }
        }
      }

      async function resolveLegacyPlan() {
        const serverPath = path.join(
          outputPath,
          ".output",
          "server",
          "index.mjs",
        );
        const assetsPath = path.join(outputPath, ".output", "public");

        if (!(await existsAsync(serverPath))) return;
        if (!(await existsAsync(assetsPath))) {
          throw new VisibleError(
            `TanStack Start assets directory not found at:\n  "${path.resolve(
              assetsPath,
            )}".`,
          );
        }

        return {
          server: toPlanPath(serverPath),
          assets: toPlanPath(assetsPath),
        };
      }

      function toPlanPath(filePath: string) {
        const relativePath = path.relative(outputPath, filePath);
        return `./${relativePath.split(path.sep).join("/")}`;
      }
    });
  }

View on GitHub (pinned to a0bd20f762)

Solutions

  1. Migrate to the current Cloudflare adapter so the dist layout (`dist/server` + `dist/client`) is used
  2. Ensure the legacy build copies public assets to `.output/public` (check Nitro `publicAssets`/prerender settings)
  3. Clean `.output` and rebuild fully
  4. If only static output is intended, use `sst.cloudflare.StaticSite`

Example fix

// before: .output/server/index.mjs exists, no .output/public
// vite.config.ts
export default defineConfig({ ... })
// after: enable public assets / upgrade adapter so dist/server + dist/client are emitted
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync } from 'fs';
if (existsSync('apps/web/.output/server/index.mjs') && !existsSync('apps/web/.output/public'))
  throw new Error('Legacy Nitro output missing .output/public; enable public assets or upgrade adapter');

Try / catch

try {
  await deploy();
} catch (e) {
  if (/assets directory not found/.test(e.message) && /\.output/.test(e.message)) console.error('Legacy .output layout incomplete; rebuild with assets enabled');
}

Prevention

When it happens

Trigger: A project emitting legacy `.output/server/index.mjs` without `.output/public`: Nitro/Nitro-based builds with prerendering disabled or public assets configured elsewhere, partial `.output` from an interrupted build.

Common situations: Older TanStack Start versions or custom Nitro presets producing server-only output; disabled static asset copying; stale partial `.output` left from a previous failed build.

Related errors


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