Why a capital letter breaks a game

Filesystems lie. Or rather, they tell different truths: ask a case-insensitive filesystem for Textures/Hero.png and it happily returns the file stored as textures/hero.png. Ask a case-sensitive one for the same path and it returns nothing, because nothing with that exact capitalisation exists.

Windows ships with NTFS configured case-insensitively by default. macOS uses HFS+ and APFS the same way. Linux uses ext4, Btrfs and most other filesystems case-sensitively, and that default has never changed. A program written on Windows can be careless about capitalisation and ship with the bug latent, invisible, because every developer machine silently corrects it. The moment that same program runs on Linux — through a compatibility layer sitting on an ext4 volume — the bug surfaces. The layer cannot fix it, because the layer is not the filesystem.

Where breakage actually lives

FROM THIS ENTRY
The bug is latent on Windows/macOScase-insensitive defaults hide it at development time
It surfaces only when the program runs on a case-sensitive filesystem (typically Linux/ext4)
The compatibility layer translates the call correctly; it cannot correct a wrong path

What the layer sees and what it cannot do

When a translated program issues a file-open call, the compatibility layer rewrites that call and passes it down to the host kernel. At the syscall boundary, the rewritten call reaches the real filesystem with the path exactly as the program provided it. If the program asked for textures/ and the directory is spelled Textures/, the kernel returns ENOENT — no such file — and the program crashes, hangs, or renders nothing.

The layer has no oracle. It does not know the developer's intent; it only knows the string it received. Some layers implement a fallback: on receiving ENOENT, re-issue the lookup with a case-folded scan of the parent directory, find the closest match, and return that instead. This works often enough to be genuinely useful. It also has a cost — a failed lookup on a case-sensitive filesystem requires a full directory scan before the fallback can proceed, and assets are looked up constantly. In a game streaming textures from disk, the wrong capitalisation on a hot path can add real time to every frame.

The scan-and-retry fallback also fails silently when a directory contains two files that differ only in case — hero.png and Hero.png both present, the program asking for HERO.PNG. The layer must guess, and any guess is wrong for at least one of them.

A mechanical keyboard pushed aside, one cable across it
FIG. 2Input starts here and ends at a photon; every queue in between is part of the latency budget.PHOTO: FOX ^.ᆽ.^= ∫ / PEXELS

The real fix, and why it is rarely applied

The correct repair is in the source: audit every file reference, normalise capitalisation, and make the asset filenames match. Studios that port their own work do this. When the compatibility layer is doing the porting instead — bridging a program whose source is unavailable — that option is closed.

A second approach sometimes taken for entire game libraries is to place the assets on a case-insensitive filesystem image and mount it. On Linux, a FAT32 or exFAT image mounted at the install directory gives the program a surface that behaves like Windows. The layer sees the mount, the kernel serves case-insensitive lookups, and the latent bugs stay latent. The drawback is storage overhead and the fact that FAT32 carries its own limitations around file size and permissions that can produce a different class of breakage.

A third approach, available on Linux since kernel 5.2 for ext4 and extended since, is per-directory case-folding: a flag on the directory itself that makes lookups within it case-insensitive. This is surgical — applied only where needed — and adds no wrapper filesystem. It requires the directory to be set up before any files are written into it, which means it cannot be applied to an existing installation without recreating it.

None of these approaches makes the underlying mismatch disappear. They displace it, or paper over it, or correct the program that caused it. The compatibility layer, sitting between the program and the kernel, can soften the impact but cannot resolve it: it translated the call correctly. The path was always wrong.

Three mitigations compared

FROM THIS ENTRY
Scan-and-retry fallbacklayer re-issues a directory scan on ENOENT; useful but adds lookup cost on hot paths
Case-insensitive filesystem image (FAT32/exFAT mounted over the install dir)no source access needed; adds storage overhead and FAT32 limitations
Per-directory case-folding (Linux kernel 5.2+, ext4)surgical, no wrapper; must be set before files are written
Ribbon and power cables crossing an open case
FIG. 3Everything crosses somewhere. The layer's work happens at seams like these, not in the code between them.

Shimwork is an independent publication about compatibility layers and API translation. It is not a software vendor, distributor, or support service.

FILED UNDER: FILESYSTEMMEDIUM ENTRY