jdx/mise · error
bootstrap compose project '{name}' services cannot be combin
Error message
bootstrap compose project '{name}' services cannot be combined with state = "absent" because compose down removes the entire project What it means
With `state = "absent"`, mise converges by running `docker compose down`, which removes the entire project — every service, network, and (per flags) volumes — not just the services you list. Because per-service selection cannot be honored on removal, combining `services` with absent state is rejected at config parse time.
Source
Thrown at src/system/compose.rs:287
impl ComposeRequest {
fn from_toml(name: String, config: ComposeTomlConfig) -> Result<Self> {
if name.is_empty() {
bail!("bootstrap compose project names cannot be empty");
}
if !config.project_dir.is_absolute() {
bail!(
"bootstrap compose project '{name}' project_dir must be absolute: {}",
config.project_dir.display()
);
}
validate_project_name(config.project_name.as_deref())?;
validate_values("profile", &config.profiles)?;
validate_values("service", &config.services)?;
validate_values("oneshot service", &config.oneshot)?;
validate_command("command", &config.command)?;
validate_command("engine_command", &config.engine_command)?;
if config.state == ComposeState::Absent && !config.services.is_empty() {
bail!(
"bootstrap compose project '{name}' services cannot be combined with state = \"absent\" because compose down removes the entire project"
);
}
if !config.wait && config.wait_timeout.is_some() {
bail!("bootstrap compose project '{name}' wait_timeout requires wait = true");
}
if config.wait_timeout == Some(0) {
bail!("bootstrap compose project '{name}' wait_timeout must be greater than zero");
}
if config.state != ComposeState::Absent
&& (config.down_volumes || config.down_images.is_some())
{
bail!(
"bootstrap compose project '{name}' down_volumes and down_images require state = \"absent\""
);
}
if config.state != ComposeState::Running && config.renew_anonymous_volumes {
bail!(View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- To remove the whole project: delete the `services`/`oneshot` lists from the absent-state table.
- To keep only selected services running: set `state = "running"` and keep the `services` list.
- If you need a separate teardown definition, use a distinct `[bootstrap.compose.<name>]` table with `state = "absent"` and no services.
Example fix
# before [bootstrap.compose.web] project_dir = "/srv/web" state = "absent" services = ["api"] # after [bootstrap.compose.web] project_dir = "/srv/web" state = "absent"
Defensive patterns
Strategy: validation
Validate before calling
if cfg.state == ComposeState::Absent {
assert!(cfg.services.is_empty() && cfg.oneshot.is_empty(),
"services/oneshot cannot be combined with state = absent");
} Prevention
- Keep a dedicated teardown table (state = "absent", no services) separate from running tables.
- When flipping a project's state, clear service selection lists at the same time.
When it happens
Trigger: A compose table sets both `state = "absent"` and a non-empty `services = [...]` (or oneshot services) list. `ComposeRequest::from_toml` bails during `mise bootstrap compose plan`/`apply` config parsing.
Common situations: Reusing one project block for both 'bring up selected services' and 'tear down' by flipping `state` while leaving `services` populated; copy-paste of a running project's config with only the state changed.
Related errors
- bootstrap compose project '{name}' down_volumes and down_ima
- bootstrap compose project '{name}' renew_anonymous_volumes r
- refusing unsafe change to bootstrap compose project '{}'; in
- bootstrap compose project names cannot be empty
- bootstrap compose project '{name}' project_dir must be absol
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/751069b6958e9943.
Report an issue: GitHub.