angular/angular-cli · error · Error

Could not find the main bundle.

Error message

Could not find the main bundle.

What it means

After locating the server output directory, the app-shell builder scans it for a file matching /^main\.(?:[a-zA-Z0-9]{16}\.)?js$/ to use as the server module bundle for prerendering. If no such file exists, it throws. The server build produced output but not a bundle named main.js (or main.<hash>.js).

Source

Thrown at packages/angular_devkit/build_angular/src/builders/app-shell/index.ts:155

  serverResult: ServerBuilderOutput,
  browserLocaleDirectory: string,
) {
  if (options.appModuleBundle) {
    return path.join(context.workspaceRoot, options.appModuleBundle);
  }

  const { baseOutputPath = '' } = serverResult;
  const outputPath = path.join(baseOutputPath, browserLocaleDirectory);

  if (!fs.existsSync(outputPath)) {
    throw new Error(`Could not find server output directory: ${outputPath}.`);
  }

  const re = /^main\.(?:[a-zA-Z0-9]{16}\.)?js$/;
  const maybeMain = fs.readdirSync(outputPath).find((x) => re.test(x));

  if (!maybeMain) {
    throw new Error('Could not find the main bundle.');
  }

  return path.join(outputPath, maybeMain);
}

async function _appShellBuilder(
  options: BuildWebpackAppShellSchema,
  context: BuilderContext,
): Promise<BuilderOutput> {
  context.logger.warn(
    'The "@angular-devkit/build-angular:app-shell" builder is deprecated as part of Angular\'s Webpack support deprecation. ' +
      'Use "@angular/build:application" instead. For more information, see https://angular.dev/tools/cli/build-system-migration.',
  );

  const browserTarget = targetFromTargetString(options.browserTarget);
  const serverTarget = targetFromTargetString(options.serverTarget);

  // Never run the browser target in watch mode.

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Ensure the server target emits a bundle named main.js (or main.<16-hex-hash>.js) directly in the server output directory.
  2. If using a custom webpack config, keep the 'main' entry/bundle name unchanged.
  3. If using the new application/esbuild server builder, use the app-shell/prerender support of '@angular/build' instead of the webpack app-shell builder, since output naming differs.
  4. Inspect the actual server output directory contents and fix outputPath configuration so it points at the folder containing the main bundle.

Example fix

// before (custom webpack config for server)
output: { filename: '[name].bundle.js' }
// after
output: { filename: '[name].js' } // emits main.js
Defensive patterns

Strategy: validation

Validate before calling

import * as fs from 'fs';
const files = fs.readdirSync(serverOutputPath);
if (!files.some((f) => /^main\.(?:[a-zA-Z0-9]{16}\.)?js$/.test(f))) {
  throw new Error(`No main.js bundle in ${serverOutputPath}: ${files.join(', ')}`);
}

Type guard

const isMainBundle = (f: string) => /^main\.(?:[a-zA-Z0-9]{16}\.)?js$/.test(f);

Try / catch

try {
  await runAppShell();
} catch (e) {
  if (String(e.message) === 'Could not find the main bundle.') {
    // inspect server output naming, fix webpack output filename or builder choice
  }
  throw e;
}

Prevention

When it happens

Trigger: The server target was configured with a custom output filename/bundle name (e.g. bundleName set or webpack config renaming main), the server outputPath points at a folder containing nested folders instead of flat bundles, or a different builder (esbuild-based server builder producing different naming) is used as serverTarget.

Common situations: Custom webpack builder configs renaming entry bundles; swapping the universal/server target to '@angular/build:application' whose output layout (e.g. server.mjs, subdirectories) no longer matches the webpack-era main.js pattern expected here; poking around dist and moving files.

Related errors


AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30). Data as JSON: /api/errors/5f8dc9227ad1fa26. Report an issue: GitHub.