Skip to content

fix(docs): resolve metadata paths with zero-width spaces#12044

Open
danyalahmed1995 wants to merge 1 commit into
facebook:mainfrom
danyalahmed1995:fix/issue-12005-zero-width-path-metadata
Open

fix(docs): resolve metadata paths with zero-width spaces#12044
danyalahmed1995 wants to merge 1 commit into
facebook:mainfrom
danyalahmed1995:fix/issue-12005-zero-width-path-metadata

Conversation

@danyalahmed1995
Copy link
Copy Markdown
Contributor

@danyalahmed1995 danyalahmed1995 commented May 21, 2026

Summary

Fixes #12005.

This PR fixes a docs metadata hash mismatch that can happen when a docs path contains U+200B ZERO WIDTH SPACE.

The original issue reported that a docs page failed to build when placed under:

docs/contribute/vulnerability-report/index.mdx

while moving the same file elsewhere worked. The repro also showed that Docusaurus wrote one generated docs metadata JSON file, but the MDX loader tried to import another.

After reproducing the issue, the key detail was that the failing folder name was not plain ASCII. In the reporter repro, the actual folder name contains two trailing zero-width spaces:

vulnerability-report<U+200B><U+200B>

So the real path is effectively:

docs/contribute/vulnerability-report<U+200B><U+200B>/index.mdx

What was found

The reporter already narrowed this down to a generated metadata hash mismatch.

I reproduced the issue on Windows with Node v24.14.1 and Docusaurus 3.10.1, and confirmed the exact mismatch:

missing/required: site-docs-contribute-vulnerability-report-index-mdx-e58.json
actual/written:   site-docs-contribute-vulnerability-report-index-mdx-b66.json

I also checked a fresh controlled Docusaurus project and found:

  • Plain ASCII docs/contribute/vulnerability-report/index.mdx passes.
  • The same path with trailing U+200B U+200B reproduces the mismatch.
  • An internal U+200B case also reproduces a similar mismatch.
  • Other Unicode paths such as Korean, CJK, NFC/NFD accents, U+200C, U+200D, U+2060, and U+00A0 were not affected in the same way.
  • Links, sidebars, category.json, explicit slug, explicit id, and cache/rename behavior did not appear to be the root cause.

So this is not a problem with the vulnerability-report folder name itself. It is a hidden Unicode path handling issue.

Root cause

Docs metadata is written using the loaded docs source string, but the MDX loader later computes the metadata JSON filename from the loader path.

For paths containing U+200B ZERO WIDTH SPACE, those two strings can differ before docuHash() is called.

That means Docusaurus can write metadata using one source string:

site-docs-contribute-vulnerability-report-index-mdx-b66.json

while the MDX loader imports metadata using a different source string:

site-docs-contribute-vulnerability-report-index-mdx-e58.json

The result is a hard build failure:

Cannot find module '@site/.docusaurus/docusaurus-plugin-content-docs/default/site-docs-contribute-vulnerability-report-index-mdx-e58.json'

Changes

This PR updates the docs content helpers so the MDX metadata import resolves back to the loaded docs source before hashing.

Instead of hashing only the MDX loader path, the metadata path now goes through the content helper mapping and uses the same source that was used when the docs metadata JSON file was created.

This keeps the generated metadata filename consistent between:

  • docs metadata generation
  • MDX loader metadata import generation

The PR also adds a guard for ambiguous metadata source keys. If two docs paths only differ in a way that would collapse to the same metadata source key, Docusaurus now reports that ambiguity clearly instead of silently choosing one and creating another confusing missing-module failure.

Regression coverage

Added tests for:

  • normal ASCII docs paths
  • trailing U+200B U+200B paths
  • internal U+200B paths
  • normal Unicode paths remaining unaffected
  • ambiguous paths that only differ by U+200B

Validation

Ran:

yarn test packages/docusaurus-plugin-content-docs/src/__tests__/contentHelpers.test.ts --runInBand
yarn test packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts packages/docusaurus-plugin-content-docs/src/__tests__/contentHelpers.test.ts --runInBand
yarn test packages/docusaurus-plugin-content-docs --runInBand
yarn workspace @docusaurus/plugin-content-docs build
git diff --check

Also manually verified before/after behavior for:

  • docs/contribute/vulnerability-report/index.mdx
  • passed before
  • passes after
  • docs/contribute/vulnerability-report<U+200B><U+200B>/index.mdx
  • failed before with e58 required vs b66 generated
  • passes after with the generated b66 metadata file
  • docs/contribute/vulnerability<U+200B>-report/index.mdx
  • failed before with mismatched metadata hash
  • passes after with the matching generated metadata file

Line-ending hygiene was also checked with git diff --check.

@meta-cla meta-cla Bot added the CLA Signed Signed Facebook CLA label May 21, 2026
@netlify
Copy link
Copy Markdown

netlify Bot commented May 21, 2026

[V2]

Built without sensitive environment variables

Name Link
🔨 Latest commit 452c4e4
🔍 Latest deploy log https://app.netlify.com/projects/docusaurus-2/deploys/6a0e6098e247770007f352cc
😎 Deploy Preview https://deploy-preview-12044--docusaurus-2.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@danyalahmed1995 danyalahmed1995 force-pushed the fix/issue-12005-zero-width-path-metadata branch from 3eae039 to 452c4e4 Compare May 21, 2026 01:32
Copy link
Copy Markdown
Collaborator

@slorber slorber left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, this looks like AI slop

Maybe it's a legit fix, but you are not testing the problem end-to-end, and only adding tests for the code you introduced, which doesn't prove anything in practice.

It remains to be proved that the problem is actually solved, and that your PR is not introducing useless code, despite it being "tested."


Before even thinking about implementing a solution, I want to see an end-to-end test case that actually fails on our CI.

Please add a dogfooding test case to our own website, for example, as I did here: #12052

  • If I remove your code, the CI must fail with the initial bug report error.
  • If I add back your code, the CI must pass, proving that your implementation solves the problem.

Also, this issue is likely to also affect other plugins, so we'd rather implement a generic solution.

@danyalahmed1995
Copy link
Copy Markdown
Contributor Author

Honestly yeah i got invested in proving my approach instead of looking at the original end to end failure , I will keep that in mind apologies for that 😅.

I am gonna do the testing you asked me to do and come back with a generic solution that doesn't affect other plugins.

Thank you for the feedback.

@danyalahmed1995
Copy link
Copy Markdown
Contributor Author

@slorber I reworked the PR around the dogfood repro path from #12052.

Locally, with the dogfood vulnerability-report<U+200B><U+200B>/index.mdx page added:

  • removing the implementation fix makes yarn build:website:fast fail with the missing generated metadata JSON import
  • restoring the fix makes the same command pass

I removed the helper-only test coverage because that was basically redundant and was mainly for proving the approach not the actual repro.

I havent made a commit for it because i am still looking for a generic approach as you asked so it doesnt effect other plugins.

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

Labels

CLA Signed Signed Facebook CLA

Projects

None yet

2 participants