Skip to content

Don't swallow errors from ExecutionConfigurationBuilder#15475

Open
afscrome wants to merge 1 commit intomicrosoft:mainfrom
afscrome:dont-swallow-configuration-errors
Open

Don't swallow errors from ExecutionConfigurationBuilder#15475
afscrome wants to merge 1 commit intomicrosoft:mainfrom
afscrome:dont-swallow-configuration-errors

Conversation

@afscrome
Copy link
Contributor

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
Contributor

🚀 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
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 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.
if (configuration.Exception is not null)
{
throw new FailedToApplyEnvironmentException();
ExceptionDispatchInfo.Throw(configuration.Exception);
Copy link
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.

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.

4 participants