Docker Compose destroy requires `ComposeFilePath` in deployment state even though teardown uses only project name
- Dominant language
- C#
- Stars
- 6.3k
- Forks
- 991
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 196
Description
## Summary
The Docker Compose destroy path currently refuses to run if `ComposeFilePath` is missing from deployment state, even though the actual teardown path uses project-name-only mode and does not pass the compose file to `docker compose down`.
This makes `aspire destroy` more fragile than necessary for Docker Compose environments and can lead to a no-op destroy with:
> No Docker Compose deployment state found for 'docker-compose'. Nothing to destroy.
## Why this looks wrong from the code
In `src/Aspire.Hosting.Docker/DockerComposeEnvironmentResource.cs`, destroy does this:
- acquires `DockerCompose:{Name}` from deployment state
- reads `savedComposeFilePath = stateSection.Data["ComposeFilePath"]?.ToString()`
- returns early with "Nothing to destroy" if that value is null or empty
But when destroy does proceed, it builds the compose context like this:
- `ProjectName = savedProjectName`
- `WorkingDirectory = savedOutputPath`
It does **not** set `ComposeFilePath` for teardown.
That matches `ContainerRuntimeBase.ComposeDownAsync(...)`, which can already run in project-name-only mode through `BuildComposeArguments(...)`.
## Expected behavior
If Aspire has enough saved state to identify the compose project, destroy should attempt teardown instead of requiring `ComposeFilePath` specifically.
At minimum, if `ProjectName` is present, I would expect destroy to try `docker compose --project-name down`.
## Related diagnostic gap
The same local deployment state file can exist for other reasons, such as saved parameter values, even when the Docker Compose section is absent or incomplete.
That makes the current message a bit misleading, because there may be local deployment state, just not the specific `ComposeFilePath` field that this path requires.
Also, the top-level destroy step clears the whole deployment state file afterward, which makes postmortem diagnosis harder.
## Source evidence
Docker Compose state is persisted only after a successful `ComposeUpAsync(...)`:
- `src/Aspire.Hosting.Docker/DockerComposeEnvironmentResource.cs`
- `stateSection.Data["OutputPath"] = outputPath;`
- `stateSection.Data["ProjectName"] = composeContext.ProjectName;`
- `stateSection.Data["ComposeFilePath"] = composeContext.ComposeFilePath;`
Destroy currently gates on `ComposeFilePath`:
- `src/Aspire.Hosting.Docker/DockerComposeEnvironmentResource.cs`
- `var savedComposeFilePath = stateSection.Data["ComposeFilePath"]?.ToString();`
- early return when it is null or empty
Destroy then tears down using project-name-only mode:
- `var composeContext = new ComposeOperationContext { ProjectName = savedProjectName, WorkingDirectory = savedOutputPath };`
`ContainerRuntimeBase.BuildComposeArguments(...)` already supports no compose file:
- `compose --project-name "{context.ProjectName}"` when `ComposeFilePath` is null
## Scenario that led me here
I ran into this while debugging a failed Docker Compose deployment and later got `No Docker Compose deployment state found ... Nothing to destroy`, even though compose-managed resources from the same project name still existed.
I cannot prove from the outside exactly which state transition dropped the field, but the current gate on `ComposeFilePath` looks stricter than the actual teardown path requires.
From my general understanding, then the flow that makes this an issue is:
`aspire deploy` -> *one or more* services does not come up -> deploy state is not written -> user tries to remove the failed deploy -> deploy cant be found as the deploy state is missing
Contributor guide
Research direction
Start in src/Aspire.Hosting.Docker/DockerComposeEnvironmentResource.cs by tracing the destroy state lookup and its ComposeFilePath guard, then read ContainerRuntimeBase.BuildComposeArguments(...) for project-name-only behavior. Done means destroy attempts teardown when ProjectName is available without requiring ComposeFilePath, while preserving the existing deployment-state handling.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp, docker-compose
- Domain
- devops, infrastructure
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100