microsoft/aspire · error · InvalidOperationException

The dashboard URL is not available in publish mode.

Error message

The dashboard URL is not available in publish mode.

What it means

GetDashboardUrlAsync resolves the dashboard's HTTP endpoint, which only exists when the app runs (run mode). In publish mode the app is generating deployment artifacts, no dashboard resource/endpoint is instantiated, so the extension refuses to proceed. It is a guard against a meaningless call rather than a runtime failure.

Solutions

  1. Call GetDashboardUrlAsync only in run mode (DcpScheduler/run path), not during publish.
  2. Check executionContext.IsPublishMode before calling and skip dashboard URL retrieval in publish mode.
  3. Restructure the code so publish-time logic does not depend on dashboard endpoints.

Example fix

// before
var url = await app.GetDashboardUrlAsync();
// after
var ctx = app.Services.GetRequiredService<DistributedApplicationExecutionContext>();
if (!ctx.IsPublishMode)
{
    var url = await app.GetDashboardUrlAsync();
}
Defensive patterns

Strategy: validation

Validate before calling

var ctx = app.Services.GetRequiredService<DistributedApplicationExecutionContext>();
if (ctx.IsPublishMode)
{
    // skip dashboard URL retrieval; return null or take alternate path
}

Type guard

static bool CanGetDashboardUrl(DistributedApplication app) =>
    !app.Services.GetRequiredService<DistributedApplicationExecutionContext>().IsPublishMode;

Try / catch

try
{
    var url = await app.GetDashboardUrlAsync(ct);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("publish mode"))
{
    url = null; // publish mode: dashboard has no runtime URL
}

Prevention

When it happens

Trigger: Calling app.GetDashboardUrlAsync() on a DistributedApplication whose DistributedApplicationExecutionContext is in publish mode — i.e. inside PublishAsDockerFile/GenerateResource pipeline or after running with --publisher / publish operations.

Common situations: Shared helper code that runs both run and publish paths calling the extension unconditionally; custom deploy pipelines invoking testing extensions during manifest generation.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting.Testing/DistributedApplicationHostingTestingExtensions.cs:74

    ///
    /// var builder = await DistributedApplicationTestingBuilder.CreateAsync&lt;Projects.MyAppHost_AppHost&gt;(options, []);
    /// await using var app = await builder.BuildAsync();
    /// await app.StartAsync();
    ///
    /// var dashboardUrl = await app.GetDashboardUrlAsync();
    /// </code>
    /// </example>
    [AspireExportIgnore(Reason = "Use the exported getDashboardUrl overload without a cancellation token.")]
    public static async Task<Uri> GetDashboardUrlAsync(
        this DistributedApplication app,
        CancellationToken cancellationToken = default)
    {
        ArgumentNullException.ThrowIfNull(app);

        var executionContext = app.Services.GetRequiredService<DistributedApplicationExecutionContext>();
        if (executionContext.IsPublishMode)
        {
            throw new InvalidOperationException(Properties.Resources.DashboardUrlPublishModeExceptionMessage);
        }

        var applicationOptions = app.Services.GetRequiredService<DistributedApplicationOptions>();
        if (applicationOptions.DisableDashboard)
        {
            throw new InvalidOperationException(Properties.Resources.DashboardDisabledExceptionMessage);
        }

        ThrowIfNotStarted(app, Properties.Resources.DashboardUrlApplicationNotStartedExceptionMessage);
        cancellationToken.ThrowIfCancellationRequested();

        await app.ResourceNotifications.WaitForResourceHealthyAsync(
            DashboardResourceName,
            WaitBehavior.StopOnResourceUnavailable,
            cancellationToken).ConfigureAwait(false);

        var applicationModel = app.Services.GetRequiredService<DistributedApplicationModel>();
        if (!applicationModel.Resources.TryGetByName(DashboardResourceName, out var resource) ||

View on GitHub (pinned to 25830f84bd)