Skip to content

Fix empty file list in ambiguous module resolution errors - #2102

Open
kwy404 wants to merge 1 commit into
react:mainfrom
kwy404:fix-ambiguous-resolution-list
Open

kwy404 wants to merge 1 commit into
react:mainfrom
kwy404:fix-ambiguous-resolution-list

Conversation

@kwy404

@kwy404 kwy404 commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Summary

When a Haste name has more than one provider, DependencyGraph turns the DuplicateHasteCandidatesError from metro-file-map into an AmbiguousModuleResolutionError. formatBundlingError (the error sent to the app) and TerminalReporter._logBundlingError (the terminal output) both build their own message for it, and list the candidates with Object.keys(he.duplicatesSet). But duplicatesSet is a Map (DuplicatesSet = Map<string, number> in metro-file-map, and HastePlugin throws with a Map), and Object.keys() of a Map is []. So both messages end with "You can delete or fix them:" and nothing after it.

The dev server hits this when two files share a Haste name, for example with resolver.enableGlobalPackages and two package.json files outside node_modules with the same name (the "multiple packages with the same name" case in resolver-test.js). Calling the formatter directly shows it:

const error = new AmbiguousModuleResolutionError(
  '/root/index.js',
  new DuplicateHasteCandidatesError(
    'shared',
    H.GENERIC_PLATFORM,
    false,
    new Map([
      ['/root/a/package.json', H.PACKAGE],
      ['/root/b/package.json', H.PACKAGE],
    ]),
  ),
);
formatBundlingError(error).message;
// "Ambiguous resolution: module '/root/index.js' tries to require 'shared', but there
// are several files providing this module. You can delete or fix them: \n\n"

The fix reads the paths from the map keys ([...he.duplicatesSet.keys()]) in both places. In formatBundlingError this also drops a .map() that only turned each path into the same string.

Changelog: [Fix] Ambiguous module resolution errors list the conflicting files instead of an empty list, in the terminal and in the app

Test plan

Added an AmbiguousModuleResolutionError test to packages/metro/src/lib/__tests__/formatBundlingError-test.js. It builds the error from a real DuplicateHasteCandidatesError with two paths and checks the whole message.

  • Before the fix it fails: the message ends right after "fix them: \n\n".
  • After the fix it passes, with both paths listed.
  • TerminalReporter has no test file, so I checked it with a throwaway test that calls _logBundlingError with the same error. Before the fix nothing follows "fix them:", after it the output lists * `/root/a.js` and * `/root/b.js` .
  • yarn jest packages/metro/src/lib/__tests__ packages/metro/src/__tests__/HmrServer-test.js packages/metro/src/Server/__tests__/Server-test.js: 20 suites, 274 tests pass.
  • eslint and prettier --check on the three changed files: clean.
  • flow focus-check on the three files: no new errors. My local flow-bin is still 0.333, so I ran it with --ignore-version; the only error it reports (the asserts syntax in flow-typed/npm/invariant_v2.x.x.js) is the same on main.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 23, 2026

This branch has not been deployed

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

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant