{"record":{"id":"64a113ac9753d9fc","repo":"microsoft/aspire","slug":"the-filesystem-spelling-of-originalpath-could-not-be-read","errorCode":null,"errorMessage":"The filesystem spelling of '{originalPath}' could not be read from '{current}'.","messagePattern":"The filesystem spelling of '(.+?)' could not be read from '(.+?)'\\.","errorType":"exception","errorClass":"DistributedApplicationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Rust/RustDockerfileGenerator.cs","lineNumber":299,"sourceCode":"                for (; i < segments.Length; i++)\n                {\n                    current = Path.Combine(current, segments[i]);\n                }\n\n                return current;\n            }\n\n            // On a case-insensitive host, File.Exists accepts a spelling that will not exist after Docker\n            // copies the context into Linux. Enumerating the parent returns the directory entry's stored\n            // casing; on case-sensitive hosts the exact candidate above is the only matching entry.\n            string[] entries;\n            try\n            {\n                entries = Directory.GetFileSystemEntries(current);\n            }\n            catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)\n            {\n                throw new DistributedApplicationException(\n                    $\"The filesystem spelling of '{originalPath}' could not be read from '{current}'.\",\n                    ex);\n            }\n\n            // APFS can treat canonically equivalent Unicode names as the same entry while returning the\n            // stored normalization form. Normalize only for matching, then keep the enumerated spelling.\n            var normalizedSegment = segments[i].Normalize(NormalizationForm.FormC);\n            current = entries.FirstOrDefault(entry =>\n                    string.Equals(Path.GetFileName(entry), segments[i], StringComparison.Ordinal))\n                ?? entries.FirstOrDefault(entry =>\n                    string.Equals(\n                        Path.GetFileName(entry).Normalize(NormalizationForm.FormC),\n                        normalizedSegment,\n                        StringComparison.OrdinalIgnoreCase))\n                ?? throw new DistributedApplicationException(\n                    $\"The filesystem spelling of '{originalPath}' could not be matched in '{current}'.\");\n        }\n","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Rust/RustDockerfileGenerator.cs#L281-L317","documentation":"ResolveFilesystemCasing walks the manifest path segment by segment to learn the true on-disk spelling (casing/normalization) of each name, because Dockerfiles must reference the exact filesystem spelling. When enumerating Directory.GetFileSystemEntries(current) fails with IOException or UnauthorizedAccessException, the library cannot continue and throws this DistributedApplicationException wrapping the underlying exception.","triggerScenarios":"Calling ValidateManifestPath (via publish-mode Dockerfile generation for a Rust app) with a manifest path whose directory cannot be enumerated: an intermediate directory was deleted between validation and enumeration, permissions deny listing, or an IO error occurs on a network/slow volume.","commonSituations":"Manifest path points into a directory removed or renamed after configuration; restricted ACLs on a CI container; a volume that returns IO errors (unmounted network share, failing disk).","solutions":["Verify the manifest path exists and every intermediate directory is readable before publishing (run Directory.GetFileSystemEntries yourself).","Fix filesystem permissions (chmod/chown/ACLs) so the publishing process can list the directory.","Recreate or remount the failing volume; check dmesg/disk health if IOException persists.","Re-enable case sensitivity or confirm the directory content matches the configured manifest path exactly."],"exampleFix":"// before\nmanifestPath = \"/app/Src/main.rs\"; // Src deleted or unreadable\n// after\nif (!Directory.Exists(\"/app/Src\")) throw new DirectoryNotFoundException(\"Regenerate or restore /app/Src before publishing\");\nmanifestPath = \"/app/src/main.rs\";","handlingStrategy":"validation","validationCode":"var dir = Path.GetDirectoryName(manifestPath);\nif (dir is null || !Directory.Exists(dir)) throw new InvalidOperationException($\"Manifest directory '{dir}' does not exist\");\n_ = Directory.GetFileSystemEntries(dir); // throws IOException/UnauthorizedAccessException early if unreadable","typeGuard":null,"tryCatchPattern":"try { GenerateManifestAsync(); }\ncatch (DistributedApplicationException ex) when (ex.InnerException is IOException or UnauthorizedAccessException) {\n    logger.LogError(ex.InnerException, \"Cannot read filesystem casing for manifest path\");\n}","preventionTips":["Verify manifest paths exist and are listable before publishing","Avoid network volumes for build contexts","Run publishing under an identity with read access to the source tree"],"tags":["filesystem","io","permissions","dockerfile"],"backgroundTag":"file-read-failed","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}