microsoft/aspire · error · DistributedApplicationException

Unable to read the output of 'cargo metadata' for the Rust…

Error message

Unable to read the output of 'cargo metadata' for the Rust app '{resourceName}'. Cargo returned invalid {ex.GetType().Name} output.

What it means

Once 'cargo metadata' exits successfully, ReadAsync passes stdout to CargoMetadata.Parse. If parsing throws any exception other than DistributedApplicationException (e.g. JsonException from malformed JSON), it is wrapped in DistributedApplicationException stating that cargo returned invalid output, preserving the original exception type name.

Solutions

  1. Run 'cargo metadata --format-version 1' manually in the resource directory and inspect stdout for non-JSON content.
  2. Remove any cargo shim/wrapper/alias so the real cargo binary is invoked, or make the wrapper pass stdout through untouched.
  3. Check for hooks or environment (RUSTFLAGS, custom config, plugin scripts) that cause cargo to emit extra stdout.
  4. Update the Rust toolchain if the installed cargo emits an unexpected metadata schema, then retry.

Example fix

// diagnose non-JSON cargo output
// before
$ which cargo
 /usr/local/bin/cargo  # a wrapper script printing banners

// after
$ which cargo
 ~/.cargo/bin/cargo     # real cargo; stdout is pure JSON
Defensive patterns

Strategy: validation

Validate before calling

# Ensure cargo emits clean JSON:
cargo metadata --format-version 1 | python -c 'import json,sys; json.load(sys.stdin)' && echo OK

Try / catch

try { /* start Rust resource */ }
catch (DistributedApplicationException ex) when (ex.Message.Contains("Cargo returned invalid"))
{ /* inspect raw cargo stdout for non-JSON content */ }

Prevention

When it happens

Trigger: cargo exits 0 but its stdout is not valid/expected 'cargo metadata --format-version 1' JSON — e.g. extra banner text, output written by a wrapper script, truncation, or a shim that prints diagnostics to stdout.

Common situations: A 'cargo' shim/alias on PATH that injects extra output; tooling that mutates cargo behavior (cargo-wrap scripts); output truncated by an intermediary; cargo printing warnings into the redirected stream in an unexpected format.

Understand the failure class

Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.

Related errors


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

Appendix: source

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

        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}");
        }

        try
        {
            return CargoMetadata.Parse(stdout);
        }
        catch (Exception ex) when (ex is not DistributedApplicationException)
        {
            throw new DistributedApplicationException(
                $"Unable to read the output of 'cargo metadata' for the Rust app '{resourceName}'. Cargo returned invalid {ex.GetType().Name} output.");
        }
    }

    internal static string FormatStandardError(
        string standardError,
        IReadOnlyDictionary<string, string> environment,
        IEnumerable<KeyValuePair<string, string?>>? inheritedEnvironment = null)
    {
        // Cargo wrappers and configuration errors can echo values from the resolved resource environment or
        // inherited variables such as CARGO_REGISTRY_TOKEN. Resource values are all user-controlled, while
        // inherited values are limited to conventional secret-bearing names to preserve useful diagnostics.
        // Redact before truncating so a value that crosses the retained-output boundary cannot leak partially.
        if (string.IsNullOrWhiteSpace(standardError))
        {
            return string.Empty;
        }

View on GitHub (pinned to 25830f84bd)