Skip to content

Treat Unicode-normalization-only renames like case-only renames - #1079

Merged
RyanZim merged 3 commits into
jprichardson:masterfrom
afonsojanu:fix/move-unicode-normalization-paths
Sep 22, 2026
Merged

RyanZim merged 3 commits into
jprichardson:masterfrom
afonsojanu:fix/move-unicode-normalization-paths

Conversation

@afonsojanu

Copy link
Copy Markdown
Contributor

Fixes #859.

Moving a file to a name that differs only in Unicode normalization form (NFC vs NFD, like café written as one precomposed character versus e plus a combining accent) throws Source and destination must not be the same. on filesystems that auto-normalize names, APFS being the common case. The two names look identical to a person, and to path.basename, but the filesystem folds them onto the same inode, so the existing "same file" check trips even though this is really just a rename.

This is the same shape of bug as #759/#801 (renaming to change letter case only), which already has a fix in checkPaths/checkPathsSync: if the basenames differ as strings but resolve to the same inode, and are equal after some normalization, treat it as a legitimate rename rather than raising the same-path error. I extended that existing check to also cover NFC-equality, alongside the case-insensitive comparison already there.

Verified against a real reproduction on macOS/APFS: moveSync/move both threw before the change and succeed after it. Added two small regression tests (move-unicode-normalization-paths.test.js and the sync equivalent) following the pattern of the existing case-insensitive tests. Full suite (736 tests) plus lint pass locally.

Moving a file to a name that differs only in Unicode normalization
form (NFC vs NFD) throws "Source and destination must not be the
same." on filesystems that auto-normalize, such as APFS, even though
the source and destination are visually identical and the user is
just renaming the file. This mirrors the case-insensitive rename bug
fixed in jprichardson#801, so it gets the same fix: when the basenames differ but
resolve to the same inode, and they're equal after either
lowercasing or NFC normalization, treat it as a rename instead of
raising the same-path error.

Fixes jprichardson#859

This comment was marked as off-topic.

Comment thread lib/util/stat.js Outdated
@RyanZim

RyanZim commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

Pushed changes to properly handle changing case & Unicode normalization format at the same time, along with tests.

@manidlou manidlou left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, thank you @afonsojanu and @RyanZim

@RyanZim
RyanZim merged commit de72292 into jprichardson:master Sep 22, 2026
21 checks passed
@RyanZim

RyanZim commented Sep 22, 2026

Copy link
Copy Markdown
Collaborator

Published in v11.4.1 🎉

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error "Source and destination must not be the same" in move-sync on unicode normalization difference

5 participants