What's wrong
PersistenceProviderUtilities.GetSafeFileName (Essentials/PersistenceProviderUtilities.cs:91) truncates and hashes a key only when encoded.Length > MaxEncodedLength (100). That limit counts UTF-16 chars, but Linux and macOS limit a file-name component to 255 bytes.
FileSystemPersistenceProvider then adds more to the name:
GetFilePath (line 233) appends the serializer's FileExtension.
StoreAsync (line 72) appends ".tmp" on top of that.
A key of multibyte characters can therefore stay under 100 chars, avoid truncation, and still produce a file name longer than 255 bytes.
Repro
This was run on Linux (ext4/tmpfs) with a console program built against current main.
var key = new string('日', 90); // 90 chars, 270 UTF-8 bytes
PersistenceProviderUtilities.GetSafeFileName(key); // returned unchanged (90 chars)
await provider.StoreAsync(key, "v");
// PersistenceProviderException
// ---> PathTooLongException: The path '/tmp/.../日日…日.json.tmp' is too long,
// or a component of the specified path is too long.
- After that,
RetrieveAsync and ExistsAsync quietly report the key as missing.
- A 300-char ASCII key works, because it gets truncated and hashed.
- The threshold is about 83 CJK characters, or fewer for emoji and other 4-byte characters.
DataHome, ConfigHome and Temp persistence all delegate storage to the file-system provider, so they fail the same way.
Why it matters
Keys derived from user content such as titles, file names or search terms routinely contain non-ASCII text. On Linux and macOS these keys can't be stored even though an equally long English key can, and the failure only shows up at runtime. Windows is unaffected because NTFS counts UTF-16 units.
Suggested fix / acceptance criteria
- Base the truncation decision on the byte length as well. For example, truncate when
Encoding.UTF8.GetByteCount(encoded) exceeds a budget of 255 minus the longest suffix that gets appended (extension plus .tmp), rounded down to something like 200 for headroom.
- When truncating, cut the prefix at a character boundary so that no surrogate pair is split.
- Make sure
IsTruncatedName still recognises the new shape.
- Add tests that store and retrieve CJK and emoji keys long enough to exceed 255 bytes, and assert round-trip success.
What's wrong
PersistenceProviderUtilities.GetSafeFileName(Essentials/PersistenceProviderUtilities.cs:91) truncates and hashes a key only whenencoded.Length > MaxEncodedLength(100). That limit counts UTF-16 chars, but Linux and macOS limit a file-name component to 255 bytes.FileSystemPersistenceProviderthen adds more to the name:GetFilePath(line 233) appends the serializer'sFileExtension.StoreAsync(line 72) appends".tmp"on top of that.A key of multibyte characters can therefore stay under 100 chars, avoid truncation, and still produce a file name longer than 255 bytes.
Repro
This was run on Linux (ext4/tmpfs) with a console program built against current
main.RetrieveAsyncandExistsAsyncquietly report the key as missing.DataHome, ConfigHome and Temp persistence all delegate storage to the file-system provider, so they fail the same way.
Why it matters
Keys derived from user content such as titles, file names or search terms routinely contain non-ASCII text. On Linux and macOS these keys can't be stored even though an equally long English key can, and the failure only shows up at runtime. Windows is unaffected because NTFS counts UTF-16 units.
Suggested fix / acceptance criteria
Encoding.UTF8.GetByteCount(encoded)exceeds a budget of 255 minus the longest suffix that gets appended (extension plus.tmp), rounded down to something like 200 for headroom.IsTruncatedNamestill recognises the new shape.