microsoft/aspire · error · InvalidOperationException

Foundry CLI did not return a model ID for model

Error message

Foundry CLI did not return a model ID for model '{modelName}'.

What it means

GetModelIdAsync runs `foundry model info <modelName>` and attempts to parse a model ID from the output, first with the modern JSON shape (TryParseModelInfo when the daemon verb is 'server') and then with the legacy parser (TryParseModelId). If neither parser finds a model ID in the CLI's output, this InvalidOperationException is thrown — the CLI responded, but not in a shape the integration recognizes.

Solutions

  1. Run `foundry model info <modelName>` manually and compare its output to what the integration expects; confirm the exact model name via `foundry model list`.
  2. Download/compile the model first (`foundry model download <modelName>`) so `model info` returns a real model ID.
  3. Update the Foundry Local CLI to a version whose output matches the supported formats, then retry.
  4. If your CLI version emits a new format, file an issue at microsoft/aspire with the raw `model info` output so the parser can be extended.

Example fix

// before: alias that is not a downloaded model yields unparsable output
.AddModel("phi-4-mini-q4-GS", "my-model")

// after: use an alias confirmed by `foundry model list` / `foundry model search`
.AddModel("phi-4-mini", "my-model")
Defensive patterns

Strategy: validation

Validate before calling

// Verify the model resolves and info output is parseable before wiring it in:
//   foundry model search <modelName>
//   foundry model info <modelName> --output json   # must contain a model id field
var psi = new ProcessStartInfo("foundry", $"model info {modelName} --output json") { RedirectStandardOutput = true, UseShellUse = false };
using var p = Process.Start(psi)!;
var output = await p.StandardOutput.ReadToEndAsync();
bool hasModelId = output.Contains("id", StringComparison.OrdinalIgnoreCase) || output.Contains("modelId", StringComparison.OrdinalIgnoreCase);

Try / catch

try
{
    await model.DownloadAsync();
}
catch (InvalidOperationException ex) when (ex.Message.Contains("did not return a model ID"))
{
    logger.LogError(ex, "Could not resolve model ID for '{Model}'. Verify the name via `foundry model list` and that the CLI output format is supported.", modelName);
}

Prevention

When it happens

Trigger: DownloadModelAsync or legacyModelId path calls GetModelIdAsync; the command exits 0 (so no exit-code error) but the output contains no recognizable model ID — e.g. the model is not downloaded/known and the CLI prints a human-readable 'not found' or empty message instead of the expected JSON or ID line.

Common situations: Requesting a model that is not present locally or misspelling its name/alias; a Foundry CLI version whose `model info` output format differs from both supported shapes (modern JSON vs legacy text); the daemon verb detection picks the wrong parsing branch for the installed CLI.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting.Foundry/FoundryLocalService.cs:526

    private static async Task<string> GetModelIdAsync(string modelName, CancellationToken cancellationToken)
    {
        var daemonVerb = await GetDaemonVerbAsync(cancellationToken).ConfigureAwait(false);
        var arguments = daemonVerb == "server"
            ? new[] { "model", "info", modelName, "--output", "json" }
            : new[] { "model", "info", modelName };
        var output = await RunFoundryCommandAsync(arguments, onOutput: null, cancellationToken).ConfigureAwait(false);

        if (daemonVerb == "server" && TryParseModelInfo(output, out var modernModelId, out _))
        {
            return modernModelId;
        }

        if (TryParseModelId(output, out var modelId))
        {
            return modelId;
        }

        throw new InvalidOperationException($"Foundry CLI did not return a model ID for model '{modelName}'.");
    }

    internal static bool TryParseEndpoint(string output, out Uri endpoint)
    {
        // Foundry CLI emits service startup lines like:
        //   Service is Started on http://127.0.0.1:50920/, PID 78399!
        // and status lines like:
        //   Model management service is running on http://127.0.0.1:50920/openai/status
        var match = s_urlRegex.Match(output);
        if (!match.Success)
        {
            endpoint = null!;
            return false;
        }

        var url = match.Value.TrimEnd(',', '.', '!', ')', ']', '}', '"', '\'');
        if (!Uri.TryCreate(url, UriKind.Absolute, out var parsedEndpoint))
        {

View on GitHub (pinned to 25830f84bd)