microsoft/aspire · error · DistributedApplicationException
The filesystem spelling of
Error message
The filesystem spelling of '{originalPath}' could not be matched in '{current}'. What it means
ResolveFilesystemCasing tries to match each path segment against the actual directory entries: first exactly (ordinal), then by Unicode Form-C-normalized comparison ignoring case. If no entry matches either way, the path segment does not exist on disk as spelled, and this exception is thrown so the Dockerfile never references a nonexistent file.
Solutions
- Correct the manifest/source path spelling to exactly match the on-disk name (check case and accents with ls).
- Rename the file on disk to the expected spelling (git mv Main.rs main.rs).
- Normalize filenames to NFC (e.g. macOS: ditto or a normalization script) when moving between APFS/HFS+ and Linux.
- Re-check that the segment actually exists — it may have been deleted.
Example fix
// before var path = "/app/SRC/main.rs"; // disk has src/ // after var path = "/app/src/main.rs"; // matches on-disk spelling exactly
Defensive patterns
Strategy: validation
Validate before calling
var fullPath = Path.GetFullPath(manifestPath);
var segments = fullPath.Split(Path.DirectorySeparatorChar, StringSplitOptions.RemoveEmptyEntries);
foreach (var seg in segments)
if (seg is not ("/" or "~") && !Directory.EnumerateFileSystemEntries(Path.GetDirectoryName(fullPath)!, Path.GetFileName(fullPath)).Any())
throw new FileNotFoundException($"Segment '{seg}' not found with exact spelling"); Try / catch
try { PublishAsync(); }
catch (DistributedApplicationException ex) when (ex.Message.Contains("could not be matched")) {
logger.LogError("A path segment spelling does not exist on disk: {Msg}", ex.Message);
} Prevention
- Copy exact file names rather than retyping them
- Normalize filenames to NFC when moving between macOS and Linux
- Keep paths lowercased consistently to avoid case-mismatch bugs
When it happens
Trigger: WithRustApp / publish-mode generation with a DockerfileBuildAnnotation sourcePath or manifest path containing a segment whose spelling (case or Unicode normalization) does not exist in the parent directory — e.g. path says 'Main.rs' but disk has 'main.rs' on a case-sensitive FS, or a decomposed (NFD) macOS name matched against an NFC string that truly differs.
Common situations: Path built by string concatenation with wrong casing; files authored on macOS (NFD) deployed to case-sensitive Linux containers; typos after renaming files; file deleted after the path was configured.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- Java application ' ' cannot be published because its…
- The Aspire skills bundle staging directory must have a…
- The filesystem spelling of
- The path ' ' configured with is outside the Deno…
- The Rust app ' ' builds from the absolute path ' '…
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/28be546bf3d69da3.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.Rust/RustDockerfileGenerator.cs:314
}
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
{
throw new DistributedApplicationException(
$"The filesystem spelling of '{originalPath}' could not be read from '{current}'.",
ex);
}
// APFS can treat canonically equivalent Unicode names as the same entry while returning the
// stored normalization form. Normalize only for matching, then keep the enumerated spelling.
var normalizedSegment = segments[i].Normalize(NormalizationForm.FormC);
current = entries.FirstOrDefault(entry =>
string.Equals(Path.GetFileName(entry), segments[i], StringComparison.Ordinal))
?? entries.FirstOrDefault(entry =>
string.Equals(
Path.GetFileName(entry).Normalize(NormalizationForm.FormC),
normalizedSegment,
StringComparison.OrdinalIgnoreCase))
?? throw new DistributedApplicationException(
$"The filesystem spelling of '{originalPath}' could not be matched in '{current}'.");
}
return current;
}
private static string BuildCargoCommand(List<string> cargoArgs)
=> string.Join(" ", new[] { "cargo", "build" }.Concat(cargoArgs.Select(ShellQuote)));
private static void ValidateCargoArgumentsDoNotContainCredentials(IReadOnlyList<string> cargoArgs, string resourceName)
{
for (var i = 0; i < cargoArgs.Count; i++)
{
string? configuration = null;
if (cargoArgs[i] == "--config" && i + 1 < cargoArgs.Count)
{
configuration = cargoArgs[++i];
}View on GitHub (pinned to 25830f84bd)