microsoft/aspire · error · DistributedApplicationException
The Rust app ' ' builds from ' ', which resolves outside…
Error message
The Rust app '{resourceName}' builds from '{manifestPath}', which resolves outside its app directory '{workingDirectory}'. Only the app directory is copied into the image. What it means
ValidateManifestPath computes the relative path from the canonicalized app directory to the canonicalized manifest and throws this DistributedApplicationException if it escapes that directory ('..', a rooted result, or a '..'/'..' + separator prefix). Only the app directory is copied into the Docker image as build context, so a manifest outside it can never be included in the generated Dockerfile — publishing stops with an explicit message instead.
Solutions
- Make the resource's app directory the nearest ancestor that actually contains Cargo.toml so the manifest is inside the build context
- Copy or vendor the needed crate into the app directory instead of referencing it via '../'
- Restructure the workspace so the published Rust app and its manifest live under one directory that becomes the image build context
Example fix
// before
builder.AddRustApp("app", "../shared/Cargo.toml"); // outside the app dir
// after
builder.AddRustApp("app", "../shared"); // app dir that contains Cargo.toml Defensive patterns
Strategy: validation
Validate before calling
var rel = Path.GetRelativePath(Path.GetFullPath(appDir), Path.GetFullPath(manifestPath, appDir));
if (Path.IsPathRooted(rel) || rel.StartsWith("..")) throw new InvalidOperationException("Manifest must resolve inside the app directory."); Type guard
bool ManifestInsideAppDir(string dir, string manifest) { var rel = Path.GetRelativePath(Path.GetFullPath(dir), Path.GetFullPath(manifest, dir)); return !Path.IsPathRooted(rel) && !rel.StartsWith(".."); } Try / catch
try { await PublishAsync(appModel); } catch (DistributedApplicationException ex) when (ex.Message.Contains("outside its app directory")) { log.LogError(ex, "Cargo manifest outside build context"); } Prevention
- Keep the Rust app and its Cargo.toml within a single directory that can serve as the Docker build context
- Avoid '../' references when locating the manifest; point the resource at the containing directory instead
- Check canonicalized (symlink-resolved) paths, not just the apparent spelling, in workspaces with linked folders
When it happens
Trigger: Publishing a RustAppResource whose Cargo.toml, after symlink resolution, resolves to a location outside workingDirectory — e.g. the manifest path contains '../..' segments or the app directory is a symlink into a sibling tree so the canonical manifest lands outside the canonical context.
Common situations: Workspace layouts where the resource directory references a sibling crate via '../shared/Cargo.toml'; symlinked directories whose canonicalization moves the manifest outside the apparent app folder; pointing the resource at a parent directory while the manifest sits below it via traversal.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- The published Rust app
- The Rust app ' ' builds from the absolute path ' '…
- DockerfileBuildAnnotation should exist after calling…
- Generated Deno Dockerfiles do not support
- Java application ' ' cannot be published because its…
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/85729123a911f0bc.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.Rust/RustDockerfileGenerator.cs:243
|| !PathNormalizer.TryResolveSymlinks(filesystemManifest, out var canonicalManifest))
{
throw new DistributedApplicationException(
$"The Rust app '{resourceName}' builds from '{manifestPath}', but its symbolic links could not be " +
"fully resolved. Publishing stops rather than accepting a partially canonicalized path.");
}
// Resolve aliases first so equivalent roots such as /var and /private/var become lexically related.
// Then only enumerate entries below the build context to recover the spelling Docker will copy.
canonicalManifest = ResolveFilesystemCasing(canonicalWorkingDirectory, canonicalManifest);
var relativeManifest = Path.GetRelativePath(canonicalWorkingDirectory, canonicalManifest);
if (Path.IsPathRooted(relativeManifest)
|| relativeManifest == ".."
|| relativeManifest.StartsWith($"..{Path.DirectorySeparatorChar}", StringComparison.Ordinal)
|| relativeManifest.StartsWith($"..{Path.AltDirectorySeparatorChar}", StringComparison.Ordinal))
{
throw new DistributedApplicationException(
$"The Rust app '{resourceName}' builds from '{manifestPath}', which resolves outside its app directory " +
$"'{workingDirectory}'. Only the app directory is copied into the image.");
}
// Rebase canonical-equivalent spellings (for example /var and /private/var on macOS) to the path
// below the build context. A Unix backslash is a legal filename character, while a Windows backslash
// is a host separator that must become a forward slash for the Linux container.
return OperatingSystem.IsWindows() ? relativeManifest.Replace('\\', '/') : relativeManifest;
}
private static string ResolveFilesystemCasing(string workingDirectory, string path)
{
var originalPath = path;
var relativePath = Path.GetRelativePath(workingDirectory, path);
if (relativePath == ".")
{
return workingDirectory;
}View on GitHub (pinned to 25830f84bd)