← All articles

Unicode Normalization Filenames: Windows Can't Find Them

You can see the file in File Explorer. You can double-click it and it opens. But the moment you type its name into a command, a script, an Excel hyperlink, a batch job or the address bar, Windows tells you "The system cannot find the file specified." The usual cause, when the file came from a Mac and its name contains an accented or non-Latin character, is Unicode normalization: filenames created on macOS are often stored in a decomposed form (NFD), while anything you type on Windows is in the composed form (NFC). The two look identical on screen but are different sequences of characters, so Windows does not consider them the same name. The fix is to rename the file so its name uses the composed form, either with a short PowerShell command or with a browser-based tool, and this article walks through both.

Why unicode normalization filenames break between Mac and Windows

Unicode gives you two ways to write many accented letters. The letter é can be a single code point (U+00E9, "composed", called NFC), or it can be a plain e followed by a separate combining accent mark (U+0065 + U+0301, "decomposed", called NFD). Screens render both as é. Spell checkers accept both. Humans cannot tell them apart.

File systems can. Windows (NTFS) compares filenames by their actual character sequence. It ignores upper- and lower-case differences, but it does not treat é and e + ◌́ as equal. So if a file called José_contract.pdf was created on a Mac and stored as Jose + ◌́_contract.pdf, and you type José_contract.pdf on a Windows keyboard, you are asking for a name that does not exist on that disk.

macOS has historically favoured the decomposed form. The older HFS+ file system converted every filename to NFD, and many Mac apps and copy tools still produce NFD names today. When those files travel to Windows by USB stick, network share, cloud sync folder or email, the decomposed name travels with them unchanged.

Which characters are affected:

  • Latin letters with accents or diacritics: José, Zoë, café, Müller, Łódź
  • Korean Hangul, which decomposes into individual letters (한글 becomes ㅎㅏㄴㄱㅡㄹ in some displays)
  • Japanese kana with dakuten or handakuten (が becomes か + ゛)
  • Vietnamese, which stacks several marks on one vowel

Plain ASCII names (report_final_v2.pdf) are never affected, which is why the problem seems random: only the files from Pierre, Zoë or your Korean colleague misbehave.

How to confirm this is really the problem

Before renaming anything, check that normalization is the culprit and not a typo, a trailing space or a wrong folder. Three quick tests:

1. Try a wildcard

Open the folder in PowerShell (right-click the folder background, choose Open in Terminal or Open PowerShell window here) and run:

Get-ChildItem Jos*.pdf

If the wildcard finds the file but typing the full name does not, the name contains characters that differ from what you typed. That is the normalization signature.

2. Compare the length

Run this in the same folder:

Get-ChildItem | ForEach-Object { "$($_.Name.Length)  $($_.Name)" }

A name like José.pdf should be 8 characters long. If PowerShell reports 9, there is an invisible extra character: the combining accent that follows the plain e.

3. Ask PowerShell directly

Get-ChildItem | Where-Object { $_.Name -ne $_.Name.Normalize('FormC') } | Select-Object Name

This lists every file in the folder whose name is not already in composed form. If your problem file appears, you have your answer.

Other places the same mismatch shows up on Windows, even though you never typed a command:

  • Excel or Word hyperlinks to local files that worked for the Mac colleague but return "Cannot open the specified file" for you.
  • Batch scripts, backup jobs or import tools configured with a filename list.
  • "Save As" offering to create a second José.pdf instead of asking to overwrite the existing one.
  • Search in some apps returning nothing for the exact name while a partial search without the accented letter finds it.

Fix 1: rename the files on Windows with PowerShell

If you are comfortable with a command line, Windows already has everything you need. .NET's Normalize('FormC') converts a decomposed name to the composed form, and Rename-Item applies it.

  1. Open the affected folder in PowerShell as described above.

  2. Preview what will change (nothing is renamed yet):

    Get-ChildItem -Recurse -File |
      Where-Object { $_.Name -ne $_.Name.Normalize('FormC') } |
      Select-Object FullName
    
  3. If the list looks right, rename:

    Get-ChildItem -Recurse -File |
      Where-Object { $_.Name -ne $_.Name.Normalize('FormC') } |
      Rename-Item -NewName { $_.Name.Normalize('FormC') }
    
  4. Repeat the -ne check from the previous section. It should now return nothing.

Notes and limits:

  • -Recurse also walks subfolders. Drop it if you only want the current folder. Folder names themselves can also be decomposed; run the command once more without -File to catch them, renaming the deepest folders first.
  • This renames files on your copy. If the files live in a synced folder (OneDrive, Dropbox, Google Drive), the rename will sync back to the Mac. That is usually what you want, since the composed name works on both sides.
  • Any hyperlink or script that referenced the old decomposed name by copy-pasting it from the Mac will now point at a name that no longer exists. In practice this is rare, because the whole problem is that people type the composed form.

Fix 2: rename in the browser without a command line

If PowerShell is not your thing, or you have a mixed pile of files and ZIP archives from several people, the free FilenameFixer web app does the same conversion with drag and drop.

  1. Open the web app in Chrome, Edge, Firefox or Safari.
  2. Drag the affected files onto the page. You can drop a whole batch at once.
  3. The tool detects names in the decomposed form and shows the composed (NFC) version it will apply.
  4. Download the renamed files and replace the originals.

A few details worth knowing:

  • Files and filenames are processed locally in your browser. They are not uploaded to a server, so a confidential contract called José_contract.pdf stays on your machine.
  • If the broken names are inside a ZIP a Mac user sent you, the separate ZIP restore tool rewrites the names inside the archive (up to 200 MB) so you can extract it normally on Windows.
  • There is also a text box for pasted text. If a colleague sent you a list of filenames in an email or spreadsheet and your lookup formulas cannot match them to the files on disk, paste the list in and copy out the normalized version.

FilenameFixer does not do anything PowerShell cannot do. It just removes the need to know which command to run, and it handles archives, which the Rename-Item approach above does not.

Stopping it from happening again

Renaming fixes today's files. To avoid the next round:

  • Ask the Mac side to zip with normalization in mind, or send through a web form. Many web upload paths normalize names on the way in, though not all do.
  • Use the Chrome extension if you upload Mac-made files to web apps. The FilenameFixer Chrome extension converts filenames to NFC automatically when you pick files in an upload dialog, so an intranet document system or ticketing tool receives the composed name from the start.
  • Keep shared project files to ASCII names where you can. jose_contract.pdf works everywhere without ever touching this issue. It is less pretty, but for anything referenced by a script, hyperlink or import list, it is the safest choice.
  • Normalize in code. If you write software that reads filenames from disk and compares them to user input, normalize both sides to NFC before comparing. Most languages have a one-line call for this (.Normalize('FormC') in .NET, unicodedata.normalize('NFC', s) in Python, str.normalize('NFC') in JavaScript).

None of this is a Windows bug or a Mac bug. Both operating systems are storing exactly the bytes they were given. The mismatch only exists because two valid spellings of the same letter met on one disk, and the quickest way to end the argument is to pick the composed form and rename.