microsoft/aspire · error · InvalidOperationException
Live rendering requires interactive output.
Error message
Live rendering requires interactive output.
What it means
DisplayLiveAsync renders a continuously updated console region (Spectre.Console live display). It requires an interactive output environment; when _hostEnvironment.SupportsInteractiveOutput is false it throws this InvalidOperationException, telling the caller to fall back to incremental static output because the callback's replacement snapshots would otherwise duplicate already-printed content.
Solutions
- Check _hostEnvironment.SupportsInteractiveOutput before calling and print incremental static lines instead.
- Catch InvalidOperationException around DisplayLiveAsync and fall back to non-live rendering.
- Run the command in a real terminal for live rendering.
- Refactor the rendering callback to supply append-only output when live regions are unavailable.
Example fix
// before
await interaction.DisplayLiveAsync(initial, updateCallback);
// after
if (hostEnvironment.SupportsInteractiveOutput)
{
await interaction.DisplayLiveAsync(initial, updateCallback);
}
else
{
await RenderStaticIncrementallyAsync(interaction, updateCallback);
} Defensive patterns
Strategy: fallback
Validate before calling
if (!hostEnvironment.SupportsInteractiveOutput)
{
await RenderStaticIncrementallyAsync(interaction, updateCallback);
return;
} Type guard
bool liveRenderingSupported = hostEnvironment.SupportsInteractiveOutput;
Try / catch
try { await interaction.DisplayLiveAsync(initial, cb); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Live rendering"))
{
await RenderStaticIncrementallyAsync(interaction, cb);
} Prevention
- Always gate live rendering on SupportsInteractiveOutput.
- Design render callbacks so static incremental output is possible.
- Run live-UI commands in a TTY only.
- Add a non-TTY test that exercises the static fallback.
When it happens
Trigger: Calling DisplayLiveAsync while the CLI output is redirected (non-TTY), --non-interactive is set, or the host environment reports non-interactive output.
Common situations: Running progress-rendering commands (e.g. run/deploy with live step updates) in CI logs or piped output; invoking the interaction service from a test host without an interactive console.
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
- Cannot perform destructive operation without confirmation…
- template
- The option must be specified when running in…
- The option must be specified when running in…
- The value ' ' is not valid for .
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/0f8b988d8f90167d.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Cli/Interaction/ConsoleInteractionService.cs:648
else
{
MessageConsole.MarkupLine($"[red]{line.EscapeMarkup()}[/]");
}
}
}
public void DisplayRenderable(IRenderable renderable)
{
MessageConsole.Write(renderable);
}
public async Task DisplayLiveAsync(IRenderable initialRenderable, Func<Action<IRenderable>, Task> callback)
{
if (!_hostEnvironment.SupportsInteractiveOutput)
{
// The callback supplies replacement snapshots, so appending them would duplicate prior
// content. Callers must define incremental static output when a live region is unavailable.
throw new InvalidOperationException("Live rendering requires interactive output.");
}
await MessageConsole.Live(initialRenderable)
.AutoClear(false)
.StartAsync(async ctx =>
{
await callback(renderable => ctx.UpdateTarget(renderable));
});
}
public void DisplayCancellationMessage(string? message = null, ConsoleOutput? consoleOverride = null)
{
GetConsoleOutput(consoleOverride).WriteLine();
DisplayMessage(KnownEmojis.StopSign, $"[teal bold]{message ?? InteractionServiceStrings.StoppingAspire}[/]", allowMarkup: true, consoleOverride: consoleOverride);
}
public async Task<bool> PromptConfirmAsync(string promptText, PromptBinding<bool>? binding = null, CancellationToken cancellationToken = default)
{View on GitHub (pinned to 25830f84bd)