Skip to content

Dev bundle with source maps crashes: "Unexpected module with full source map found" #1779

Open

Description

@singh-sukhmanjit

Description

Bundling with --dev true and a --sourcemap-output set crashes with:

Error: Unexpected module with full source map found:
at processNextModule (metro-source-map/src/source-map.js)
at workLoop (metro-source-map/src/source-map.js)
at fromRawMappingsImpl (metro-source-map/src/source-map.js)
at fromRawMappingsNonBlocking (metro-source-map/src/source-map.js)
at sourceMapGeneratorNonBlocking (metro/src/DeltaBundler/Serializers/sourceMapGenerator.js)
at sourceMapStringNonBlocking (metro/src/DeltaBundler/Serializers/sourceMapString.js)
at Server._serializeGraph (metro/src/Server.js)
at Server.build (metro/src/Server.js)
at runBuild (metro/src/index.flow.js)

This reproduces reliably on an Expo SDK 56 project (metro/metro-source-map/metro-runtime 0.84.4 via @expo/metro@56.0.0, react-native@0.85.3), running:

react-native bundle --entry-file index.js --platform ios --dev true --reset-cache

--bundle-output out.jsbundle --sourcemap-output out.jsbundle.map

It is not reproducible with --dev false (with or without --minify), so this only affects development source maps, not production/release bundles.

It is not reproducible with npx expo run:ios.

It is reproducible when building through Xcode.

Root cause (as far as I could trace it)

fromRawMappingsImpl in metro-source-map/src/source-map.js throws whenever a module's map is neither an array of raw mapping tuples nor a VlqMap. In this repro, one or more modules' data.map ends up holding an object shaped like a functionMap ({__version, __count, __names, ...}) instead — i.e. the same value that correctly appears under that module's separate data.functionMap field. I was not able to fully pin down why map and functionMap end up holding the same value inside metro-transform-worker@0.84.4's per-module transform for this project — it affects a scattered, unrelated set of files (several @formatjs/* internals and a couple of plain application .js files with nothing unusual about their size or structure), which suggests a general transform-worker quirk rather than something specific to one file.

I noticed main has since replaced the result.rawMappings mechanism in metro-transform-worker with a decodedMap/tuplesFromBabelDecodedMap approach, so this exact path may already be gone upstream. However, the defensive check in metro-source-map's fromRawMappingsImpl itself is unchanged on main, and seems worth hardening regardless of the root cause: today, one module with an unexpected map shape aborts source map generation for the entire bundle, which seems more fragile than necessary.

Activity

  1. singh-sukhmanjit commented on Jul 15, 2026

    @singh-sukhmanjit
    Author

    I dug into this and have a proposed fix — pasting it here rather than opening a PR for now.

    The throw happens in fromRawMappingsImpl in metro-source-map/src/source-map.js. Since the malformed module's contribution is already unusable either way, the least disruptive fix is to skip mappings for just that one module (matching the existing behavior for a null map) instead of aborting source map generation for the whole bundle.

    --- a/packages/metro-source-map/src/source-map.js
    +++ b/packages/metro-source-map/src/source-map.js
    @@ -208,9 +208,13 @@ function fromRawMappingsImpl(
         } else if (Array.isArray(map)) {
           addMappingsForFile(generator, map, mod, carryOver);
         } else if (map != null) {
    -      throw new Error(
    -        `Unexpected module with full source map found: ${mod.path}`,
    +      // Some modules (observed for metro-runtime's require.js polyfill under
    +      // certain transform-worker configurations) end up with a non-array,
    +      // non-source-map value in `map` instead of raw mapping tuples. Skip
    +      // source mappings for that single module rather than aborting the
    +      // whole bundle/sourcemap build.
    +      console.warn(
    +        `metro-source-map: skipping source map for module with unexpected map shape: ${mod.path}`,
         }
         carryOver = carryOver + countLines(code);
         return false;
  2. robhogan commented on Jul 24, 2026

    @robhogan
    Collaborator

    Thanks for digging in to this. Source map handling in particular has changed a lot in the last few weeks. I’d be interested to know if there’s a repro without Expo and particularly if it still repros on RN 0.87 (currently in RC)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions