Skip to content

Don't swallow errors from ExecutionConfigurationBuilder#15475

Merged
davidfowl merged 1 commit intomicrosoft:mainfrom
afscrome:dont-swallow-configuration-errors
Mar 29, 2026
Merged

Don't swallow errors from ExecutionConfigurationBuilder#15475
davidfowl merged 1 commit intomicrosoft:mainfrom
afscrome:dont-swallow-configuration-errors

Conversation

@afscrome
Copy link
Copy Markdown
Collaborator

Description

Don't swallow errors if a resource fails to start due to an exception from ExecutionConfigurationBuilder.

Some improvements could be made to avoid the massive stack trace the current error gives, but getting an error is a big improvement over the reosurce showing FailedToStart without any logs to suggest why.

One way to encounter this is:

var nginx = builder.AddContainer("nginx", "nginx", "latest");

builder.AddContainer("test", "nginx")
       .WithArgs(nginx.GetEndpoint("doesnot-exist"));

Which now gives the error:

 Failed to create container resource test
System.AggregateException: One or more errors occurred while resolving resource configuration. (The endpoint `doesnot-exist` is not defined for the resource `nginx`.)
 ---> System.InvalidOperationException: The endpoint `doesnot-exist` is not defined for the resource `nginx`.
   at Aspire.Hosting.ApplicationModel.EndpointReference.get_EndpointAnnotation() in s:\aspire\src\Aspire.Hosting\ApplicationModel\EndpointReference.cs:line 24
   at Aspire.Hosting.ApplicationModel.EndpointReferenceExpression.<>c__DisplayClass10_0.<<GetValueAsync>g__ResolveValueWithAllocatedAddress|0>d.MoveNext() in s:\aspire\src\Aspire.Hosting\ApplicationModel\EndpointReference.cs:line 345
--- End of stack trace from previous location ---
   at Aspire.Hosting.ApplicationModel.EndpointReferenceExpression.GetValueAsync(ValueProviderContext context, CancellationToken cancellationToken) in s:\aspire\src\Aspire.Hosting\ApplicationModel\EndpointReference.cs:line 339
   at Aspire.Hosting.ApplicationModel.ExpressionResolver.EvalValueProvider(IValueProvider vp, ValueProviderContext context) in s:\aspire\src\Aspire.Hosting\ApplicationModel\ExpressionResolver.cs:line 50
   at Aspire.Hosting.ApplicationModel.ExpressionResolver.ResolveInternalAsync(Object value, ValueProviderContext context) in s:\aspire\src\Aspire.Hosting\ApplicationModel\ExpressionResolver.cs:line 83
   at Aspire.Hosting.ApplicationModel.ExpressionResolver.ResolveAsync(IValueProvider valueProvider, ValueProviderContext context, CancellationToken cancellationToken) in s:\aspire\src\Aspire.Hosting\ApplicationModel\ExpressionResolver.cs:line 92
   at Aspire.Hosting.ApplicationModel.ResourceExtensions.GetValue(IResource resource, DistributedApplicationExecutionContext executionContext, String key, IValueProvider valueProvider, ILogger logger, CancellationToken cancellationToken) in s:\aspire\src\Aspire.Hosting\ApplicationModel\ResourceExtensions.cs:line 629
   at Aspire.Hosting.ApplicationModel.ResourceExtensions.ResolveValueAsync(IResource resource, DistributedApplicationExecutionContext executionContext, ILogger logger, Object value, String key, CancellationToken cancellationToken) in s:\aspire\src\Aspire.Hosting\ApplicationModel\ResourceExtensions.cs:line 534
   at Aspire.Hosting.ApplicationModel.ExecutionConfigurationGathererContext.ResolveAsync(IResource resource, ILogger resourceLogger, DistributedApplicationExecutionContext executionContext, CancellationToken cancellationToken) in s:\aspire\src\Aspire.Hosting\ApplicationModel\ExecutionConfigurationGathererContext.cs:line 52
   --- End of inner exception stack trace ---
   at Aspire.Hosting.Dcp.DcpExecutor.CreateContainerAsync(RenderedModelResource cr, ILogger resourceLogger, CancellationToken cancellationToken) in s:\aspire\src\Aspire.Hosting\Dcp\DcpExecutor.cs:line 2350
   at Aspire.Hosting.Dcp.DcpExecutor.<>c__DisplayClass82_0.<<CreateContainersAsync>g__CreateContainerAsyncCore|0>d.MoveNext() in s:\aspire\src\Aspire.Hosting\Dcp\DcpExecutor.cs:line 2072

Fixes # (issue)

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No
  • Does the change require an update in our Aspire docs?

Copilot AI review requested due to automatic review settings March 21, 2026 22:01
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 21, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 15475

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 15475"

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Stops swallowing exceptions captured during execution-configuration resolution so resource startup failures surface actionable errors (instead of silently transitioning to FailedToStart).

Changes:

  • Preserve and rethrow ExecutionConfigurationBuilder/resolution exceptions using ExceptionDispatchInfo.Throw(...) for executables.
  • Preserve and rethrow ExecutionConfigurationBuilder/resolution exceptions using ExceptionDispatchInfo.Throw(...) for containers (while keeping existing FailedToApplyEnvironmentException behavior for run-args failures).

Comment on lines 1872 to 1875
if (configuration.Exception is not null)
{
throw new FailedToApplyEnvironmentException();
ExceptionDispatchInfo.Throw(configuration.Exception);
}
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change makes configuration.Exception (from ExecutionConfigurationGathererContext.ResolveAsync) propagate instead of being converted into FailedToApplyEnvironmentException. Please add a unit test in DcpExecutorTests that exercises a failing value-provider resolution (e.g., missing endpoint reference) and asserts that the failure is surfaced via error logging / OnResourceFailedToStart rather than being silently swallowed.

Copilot uses AI. Check for mistakes.
Comment thread src/Aspire.Hosting/Dcp/DcpExecutor.cs Outdated
Comment on lines 2350 to 2353
ExceptionDispatchInfo.Throw(configuration.Exception);
}
if (failedToApplyRunArgs)
{
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above for containers: please add coverage for the configuration.Exception path in container startup so regressions don’t reintroduce the "FailedToStart with no logs" behavior (assert an error is logged and the container is marked failed to start).

Suggested change
ExceptionDispatchInfo.Throw(configuration.Exception);
}
if (failedToApplyRunArgs)
{
resourceLogger.LogError(configuration.Exception, "Failed to configure container startup.");
throw new FailedToApplyEnvironmentException();
}
if (failedToApplyRunArgs)
{
resourceLogger.LogError("Failed to apply environment configuration for container startup.");

Copilot uses AI. Check for mistakes.
Comment thread src/Aspire.Hosting/Dcp/DcpExecutor.cs Outdated
if (configuration.Exception is not null)
{
throw new FailedToApplyEnvironmentException();
ExceptionDispatchInfo.Throw(configuration.Exception);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use InnerException property to remember the original one (contiguration.Exception) when constructing the FailedToApplyEnvironmentException?

I am also not thrilled by this code using ExceptionDispatchInfo--seems like a low-level API that is not really necessary here. Maybe we can eliminate it as part of this PR.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did it for consistency with every other place that throws the exception. Happy to change those if desired.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do. Thank you!

@afscrome afscrome force-pushed the dont-swallow-configuration-errors branch from fce9ed4 to 4d498b1 Compare March 28, 2026 09:11
…lder.StartAsync()`

- The implementation only occurred around part of the startup process, so it was still possible to see cancellation ex
- It impacted all cancellations, (including test timeouts) which was undesirable.

To fix this, I've taken an alternative solution by moving the suppression logic into `DistributedApplication`.
- `StartAsync()` will always throw on a cancellation as if you're calling `StartAsync()`, you're probably wanting to do something with the application once `StartAsync()` finishes.
- `RunAsync()` however suppresses the cancellation exception when`IHostApplicationLifetime.ApplicationStopping.IsCancellationRequested` (which is how `ctrl+c` stops the host)
@afscrome afscrome force-pushed the dont-swallow-configuration-errors branch from 4d498b1 to 86a3b1f Compare March 28, 2026 09:13
@davidfowl davidfowl merged commit d9331c5 into microsoft:main Mar 29, 2026
256 checks passed
@afscrome afscrome deleted the dont-swallow-configuration-errors branch April 10, 2026 20:28
@joperezr joperezr added this to the 13.3 milestone Apr 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants