microsoft/aspire · error · DistributedApplicationException

'cargo metadata' for the Rust app

Error message

'cargo metadata' for the Rust app '{resourceName}' did not complete within {s_timeout.TotalSeconds:0} seconds.

What it means

ReadAsync waits for 'cargo metadata' with a fixed timeout (s_timeout). If the process does not exit in time — and the caller's own cancellation token was not the cause — the reader kills the cargo process and throws DistributedApplicationException reporting the timeout in seconds.

Solutions

  1. Warm the workspace first: run 'cargo metadata' or 'cargo fetch' once manually so subsequent calls are fast.
  2. Check for competing cargo processes or stale lock files (~/.cargo/package cache lock, target dir lock) and remove them.
  3. Reduce workspace size or point the resource at the specific crate directory instead of a huge monorepo root.
  4. If offline, vendor dependencies or ensure a reachable crates.io mirror; retry the App Host run after the stall is cleared.

Example fix

// shell — pre-warm cargo so apphost metadata call is fast
// before
$ aspire run   # cargo metadata times out on cold cache

// after
$ cargo fetch  # or: cargo metadata --format-version 1 > /dev/null
$ aspire run
Defensive patterns

Strategy: retry

Validate before calling

// Warm cargo caches before starting the apphost:
cargo fetch || true

Try / catch

try { /* start Rust resource */ }
catch (DistributedApplicationException ex) when (ex.Message.Contains("did not complete within"))
{ /* check for cargo locks/network stalls, then retry once warmed */ }

Prevention

When it happens

Trigger: 'cargo metadata' run against a Rust workspace takes longer than s_timeout seconds: extremely large workspace, first-build index/download stalls, network-bound registry updates, or cargo hanging waiting for a package lock.

Common situations: Cold CI machines downloading the crate index/dependencies on first metadata call; enormous monorepo workspaces; cargo blocked on a file lock from another cargo process; offline environment where cargo stalls on network access; very slow disk.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting.Rust/CargoMetadataReader.cs:111

                $"Unable to start 'cargo' to inspect the Rust app '{resourceName}'. Install Rust from https://www.rust-lang.org/tools/install " +
                $"or supply your own Dockerfile in '{workingDirectory}'. {ex.Message}", ex);
        }

        // Drain both redirected streams concurrently so a full pipe cannot block cargo before it exits.
        var stdoutTask = process.StandardOutput.ReadToEndAsync(CancellationToken.None);
        var stderrTask = process.StandardError.ReadToEndAsync(CancellationToken.None);

        using var timeoutSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
        timeoutSource.CancelAfter(s_timeout);

        try
        {
            await process.WaitForExitAsync(timeoutSource.Token).ConfigureAwait(false);
        }
        catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested)
        {
            TryKillProcess(process);
            throw new DistributedApplicationException(
                $"'cargo metadata' for the Rust app '{resourceName}' did not complete within {s_timeout.TotalSeconds:0} seconds.");
        }
        catch (OperationCanceledException)
        {
            TryKillProcess(process);
            throw;
        }

        var stdout = await stdoutTask.ConfigureAwait(false);
        var stderr = await stderrTask.ConfigureAwait(false);

        if (process.ExitCode != 0)
        {
            var diagnostic = FormatStandardError(stderr, environment, startInfo.Environment);
            var diagnosticSuffix = diagnostic.Length > 0 ? $" {diagnostic}" : string.Empty;
            throw new DistributedApplicationException(
                $"'cargo metadata' failed for the Rust app '{resourceName}' with exit code {process.ExitCode}.{diagnosticSuffix}");
        }

View on GitHub (pinned to 25830f84bd)