vitejs/vite · error · Error

No corresponding legacy entry chunk found for ${htmlFilename

Error message

No corresponding legacy entry chunk found for ${htmlFilename}

What it means

Thrown in transformIndexHtml when the legacy entry chunk mapping is missing for the current HTML entry. The facadeToLegacyChunkMap is populated when the legacy bundle's transformIndexHtml runs (line 725), recording each facadeModuleId to its legacy chunk fileName. If the modern bundle's HTML transform runs and can't find the corresponding legacy entry, it means the legacy bundle was either not generated or its HTML transform didn't record the entry before the modern one needed it.

Source

Thrown at packages/plugin-legacy/src/index.ts:850

          tag: 'script',
          attrs: {
            nomodule: genModern,
            crossorigin: true,
            // we set the entry path on the element as an attribute so that the
            // script content will stay consistent - which allows using a constant
            // hash value for CSP.
            id: legacyEntryId,
            'data-src': toAssetPathFromHtml(
              legacyEntryFilename,
              chunk.facadeModuleId!,
              config,
            ),
          },
          children: systemJSInlineCode,
          injectTo: 'body',
        })
      } else {
        throw new Error(
          `No corresponding legacy entry chunk found for ${htmlFilename}`,
        )
      }

      // 6. inject dynamic import fallback entry
      if (legacyPolyfillFilename && legacyEntryFilename && genModern) {
        tags.push({
          tag: 'script',
          attrs: { type: 'module' },
          children: detectModernBrowserCode,
          injectTo: 'head',
        })
        tags.push({
          tag: 'script',
          attrs: { type: 'module' },
          children: dynamicFallbackInlineCode,
          injectTo: 'head',
        })

View on GitHub (pinned to 89620f09af)

Solutions

  1. Avoid customizing build.rolldownOptions.output when using plugin-legacy — the plugin injects its own legacy output configuration.
  2. Check that no other enforce:'post' plugin with transformIndexHtml runs before plugin-legacy's legacy HTML pass.
  3. Update plugin-legacy and Vite to compatible versions.
  4. If the issue persists, file a bug with a minimal multi-output reproduction.
Defensive patterns

Strategy: validation

Validate before calling

// Ensure no conflicting output customizations when using plugin-legacy
function validateLegacyOutputConfig(config) {
  const output = config.build?.rollupOptions?.output
  if (output && !Array.isArray(output) && typeof output !== 'string') {
    if (output.format && output.format !== 'esm') {
      console.warn('plugin-legacy expects esm output; custom format may break entry mapping')
    }
  }
}

Try / catch

try {
  await build({ plugins: [legacy()], ...minimalConfig })
} catch (e) {
  if (e.message.includes('No corresponding legacy entry chunk')) {
    console.error('Legacy entry mapping failed. Simplify output config and check plugin order.')
  }
  throw e
}

Prevention

When it happens

Trigger: genLegacy is true but the legacy bundle generation was skipped or failed silently. Can occur when renderLegacyChunks is true but the legacy output configuration is not properly generated (e.g., due to custom rolldownOptions.output manipulation), or when plugin hook ordering causes the modern HTML transform to run before the legacy one records its chunk.

Common situations: Custom output configurations that interfere with plugin-legacy's dual-output injection (lines 547-559). Using build.rollupOptions.output as a function or in unexpected shapes. Plugin ordering conflicts where another enforce:'post' plugin runs transformIndexHtml before plugin-legacy's legacy pass.

Related errors


AI-assisted analysis of vitejs/vite@89620f09af (2026-08-03). Data as JSON: /data/errors/d03ff8403c9c79ea.json. Report an issue: GitHub.