microsoft/aspire · error · DistributedApplicationException

The Rust app ' ' builds from ' ', but its symbolic links…

Error message

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.

What it means

ValidateManifestPath calls PathNormalizer.TryResolveSymlinks on both the app working directory and the full manifest path; if either cannot be fully canonicalized it throws this DistributedApplicationException. Publishing needs fully resolved paths so it can verify the manifest lies inside the build context and compute the Docker COPY path; accepting a partially canonicalized path could silently produce a wrong or unsafe build context. The library stops rather than guessing.

Solutions

  1. Inspect and fix the symlinks in the app directory path — remove dangling or cyclic links (ls -l / readlink -f)
  2. Replace symlinked paths with the real target directory when configuring the resource
  3. Verify the manifest path and working directory exist and are readable before publishing

Example fix

// before
ln -s /nonexistent/target ../rust-app  # dangling symlink
builder.AddRustApp("app", "../rust-app");
// after
ln -s /real/path/rust-app ../rust-app   # or use the real path directly
builder.AddRustApp("app", "/real/path/rust-app");
Defensive patterns

Strategy: validation

Validate before calling

if (!PathNormalizer.TryResolveSymlinks(Path.GetFullPath(appDir), out _)) throw new InvalidOperationException("App directory contains unresolvable symlinks.");

Type guard

bool HasResolvableSymlinks(string dir) => PathNormalizer.TryResolveSymlinks(Path.GetFullPath(dir), out _);

Try / catch

try { await PublishAsync(appModel); } catch (DistributedApplicationException ex) when (ex.Message.Contains("symbolic links")) { log.LogError(ex, "Unresolvable symlinks in Rust app path"); }

Prevention

When it happens

Trigger: Publishing a RustAppResource when TryResolveSymlinks fails for the working directory or manifest path — e.g. dangling symlinks, symlink loops, or filesystem entries that disappear while canonicalizing (common with linked monorepo checkouts or network/overlay filesystems).

Common situations: App directory reached through a broken or cyclic symlink; macOS/Linux symlinked project folders (e.g. ~/projects -> /volume/projects) where resolution hits an unreadable link; container/overlay filesystems where the link target does not exist.

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


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/56245a32490f688e. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.Rust/RustDockerfileGenerator.cs:227

        if (Path.IsPathRooted(manifestPath))
        {
            throw new DistributedApplicationException(
                $"The Rust app '{resourceName}' builds from the absolute path '{manifestPath}'. Publishing needs a path " +
                $"relative to its app directory '{workingDirectory}'.");
        }

        var platformManifestPath = OperatingSystem.IsWindows()
            ? manifestPath.Replace('\\', Path.DirectorySeparatorChar).Replace('/', Path.DirectorySeparatorChar)
            : manifestPath;

        var filesystemWorkingDirectory = Path.GetFullPath(workingDirectory);
        var filesystemManifest = Path.GetFullPath(platformManifestPath, workingDirectory);

        if (!PathNormalizer.TryResolveSymlinks(filesystemWorkingDirectory, out var canonicalWorkingDirectory)
            || !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.");

View on GitHub (pinned to 25830f84bd)