Skip to content

Dev source maps break symbolication when any JSON module is bundled (webpack://json|/... is not a valid URL) #1464

Description

@JoonDong2

Describe the bug

In development, importing any JSON file (project-local or from node_modules) makes SourceMapPlugin emit a source named
webpack://json|/abs/path/file.json. That is not a valid URL, so new SourceMapConsumer(map) throws TypeError: Invalid URL, and
the whole map becomes unusable: /symbolicate answers 500 for every frame in that bundle, not just the offending one.

Expected: JSON modules do not affect symbolication of the rest of the bundle.
Actual: /symbolicate returns 500 and the dev server logs Failed to symbolicate { error: 'Invalid URL' }.

In React Native this shows up as LogBox reporting "This call stack is not symbolicated. Some features are unavailable such as viewing
the function name or tapping to open files." with frames pointing at bundle offsets (index.bundle:176:1823) instead of source
locations (observed in an RN 0.87.1 app on the iOS simulator).

System Info

System:
  OS: macOS 26.2
  CPU: (8) arm64 Apple M2
  Memory: 78.06 MB / 16.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 24.15.0
    path: ~/.nvm/versions/node/v24.15.0/bin/node
  Yarn:
    version: 4.17.1
    path: ~/.nvm/versions/node/v24.15.0/bin/yarn
  npm:
    version: 11.12.1
    path: ~/.nvm/versions/node/v24.15.0/bin/npm
  Watchman:
    version: 2026.01.12.00
    path: /opt/homebrew/bin/watchman
Managers:
  CocoaPods:
    version: 1.16.2
    path: /opt/homebrew/bin/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 25.2
      - iOS 26.2
      - macOS 26.2
      - tvOS 26.2
      - visionOS 26.2
      - watchOS 26.2
  Android SDK: Not Found
IDEs:
  Android Studio: 2025.3 AI-253.29346.138.2531.14876573
  Xcode:
    version: 26.2/17C52
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.18
    path: /opt/homebrew/opt/openjdk@17/bin/javac
  Ruby:
    version: 3.3.0
    path: ~/.rbenv/shims/ruby
npmPackages:
  "@react-native-community/cli":
    installed: 20.1.0
    wanted: 20.1.0
  react:
    installed: 19.2.3
    wanted: 19.2.3
  react-native:
    installed: 0.86.0
    wanted: 0.86.0
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: Not found
  newArchEnabled: Not found
iOS:
  hermesEnabled: Not found
  newArchEnabled: Not found

Re.Pack Version

5.2.5 (dist/plugins/SourceMapPlugin.js is byte-identical in 5.3.0)

Reproduction

No separate repository: it is a stock Re.Pack app plus one JSON import. All files are inline below.

Steps to reproduce

A plain app (RN 0.86.0, @callstack/repack 5.2.5, @rspack/core 1.7.12) with the standard template config:

// rspack.config.mjs
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import * as Repack from '@callstack/repack';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

export default {
  context: __dirname,
  entry: './index.js',
  resolve: { ...Repack.getResolveOptions() },
  module: {
    rules: [
      {
        test: /\.[cm]?[jt]sx?$/,
        type: 'javascript/auto',
        use: { loader: '@callstack/repack/babel-swc-loader', parallel: true, options: {} },
      },
      ...Repack.getAssetTransformRules(),
    ],
  },
  plugins: [new Repack.RepackPlugin()],
};
// index.js
import { AppRegistry } from 'react-native';
import data from './data.json'; // <- the only difference from the working app

AppRegistry.registerComponent('Vanilla', () => () => null);
setTimeout(() => { throw new Error('probe ' + data.name); }, 1);
// data.json
{ "name": "local-json" }
react-native start --port 8081

# trigger the compile, then look at the map
curl -s -o /dev/null 'http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false'
curl -s 'http://localhost:8081/index.bundle.map?platform=ios' | jq -r '.sources[] | select(startswith("webpack://json|"))'
# -> webpack://json|/abs/path/to/app/data.json

curl -i -X POST http://localhost:8081/symbolicate -H 'content-type: application/json' \
  -d '{"stack":[{"file":"http://localhost:8081/index.bundle?platform=ios&dev=true&minify=false","lineNumber":1,"column":1,"methodName":"x"}]}'
# -> HTTP/1.1 500 Internal Server Error

Results from our runs (the three variants were separate entry files; everything else identical):

entry map sources invalid-URL sources SourceMapConsumer /symbolicate
no JSON import (control) 675 0 OK 200, frame resolves to the entry file
project-local data.json 676 1 TypeError: Invalid URL 500 (also for frames 1:1 and 500:20, which have no mapping)
require('react-native/package.json') 676 1 TypeError: Invalid URL 500

Cause

dist/plugins/SourceMapPlugin.js, devToolsmoduleFilenameTemplate:

const [prefix, ...parts] = info.resourcePath.split('/');

// prefixed modules like React DevTools Backend
if (prefix !== '.' && prefix !== '..') {
  const resourcePath = parts.filter((part) => part !== '..').join('/');
  return `webpack://${prefix}/${resourcePath}`;
}

The branch is meant for prefixed modules such as the React DevTools backend. But JSON modules get a type prefix in their identifier
(json|/abs/path/file.json; we only checked JSON, other non-javascript/auto module types may behave the same), so prefix becomes
json| and the result has a | in the host position of the URL, which WHATWG URL rejects. (| is fine in a path: webpack://ok/a|b.js
and json|/abs/a.json both parse.)

source-map parses every source name with new URL(name, base) (lib/util.js, createSafeHandler), so one invalid name fails the whole map.

Only the dev path is affected. Without compiler.options.devServer, defaultModuleFilenameTemplateHandler returns
info.absoluteResourcePath, which has no scheme, so the same | is harmless there.

Suggested fix

Percent-encode the prefix, or take the prefixed-module branch only when the prefix is URL-safe:

if (prefix !== '.' && prefix !== '..') {
  const resourcePath = parts.filter((part) => part !== '..').join('/');
  return `webpack://${encodeURIComponent(prefix)}/${resourcePath}`;
}

That yields webpack://json%7C/abs/path/file.json. On our side we apply the same rename to the map as a workaround, and /symbolicate
then resolves frames normally. We did not patch Re.Pack itself.

output.devtoolModuleFilenameTemplate is not a workaround: the plugin reads it into a commented-out local and ignores it, so there is no
config-level escape hatch.

Additional notes

  • Tested on 5.2.5 with a plain app. We could not run the plain app on 5.3.0 (no matching RN 0.86 install at hand), but SourceMapPlugin.js
    is byte-identical between the two, and a larger app on 5.3.0 produces the same webpack://json|/... source names.
  • The dev server log line is Failed to symbolicate { reqId: 'req-4', error: 'Invalid URL' }, so the reason is visible, but nothing points at
    the JSON module as the trigger.

Activity

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