nikivdev/code · error
No lifecycle down action found. Define task 'down', set [lif
Error message
No lifecycle down action found. Define task 'down', set [lifecycle].down_task, or enable [lifecycle.domains] cleanup in {} What it means
run_down checks that at least one teardown action exists and ran: a 'down' task, an explicit [lifecycle].down_task, or a [lifecycle.domains] cleanup. If neither the task chain nor any domain action ran, it bails pointing at the flow.toml path. Like run_up, it's a config-completeness guard.
Source
Thrown at src/lifecycle.rs:79
if !task_ran && lifecycle.down_task.is_none() {
processes::kill_processes(KillOpts {
config: project.flow_path.clone(),
task: None,
pid: None,
all: true,
force: false,
timeout: 5,
})?;
task_ran = true;
}
let mut domain_action_ran = false;
if let Some(domains_cfg) = lifecycle.domains.as_ref() {
domain_action_ran = run_domains_down(domains_cfg)?;
}
if !task_ran && !domain_action_ran {
bail!(
"No lifecycle down action found. Define task 'down', set [lifecycle].down_task, or enable [lifecycle.domains] cleanup in {}",
project.flow_path.display()
);
}
Ok(())
}
fn run_required_task(config_path: &Path, task_name: &str, args: Vec<String>) -> Result<bool> {
match run_task(config_path, task_name, args) {
Ok(()) => Ok(true),
Err(err) if is_task_not_found(&err) => {
bail!("lifecycle task '{}' not found", task_name);
}
Err(err) => Err(err),
}
}
View on GitHub (pinned to a747e741ae)
Solutions
- Add a `down` task to flow.toml under [tasks]
- Or set [lifecycle] down_task = "teardown" pointing at an existing task
- Or configure [lifecycle.domains] so a domain cleanup action can run
Example fix
// before (flow.toml) [tasks] up = "docker compose up -d" // after [tasks] up = "docker compose up -d" down = "docker compose down" [lifecycle] down_task = "down"
Defensive patterns
Strategy: validation
Validate before calling
let cfg = std::fs::read_to_string("flow.toml")?;
let has_down = cfg.contains("down_task")
|| cfg.lines().any(|l| l.starts_with("down "))
|| cfg.contains("[lifecycle.domains]");
if !has_down { eprintln!("flow.toml defines no down action"); } Try / catch
if let Err(e) = run_down(&project, opts) {
if e.to_string().contains("No lifecycle down action found") {
eprintln!("Add a 'down' task, [lifecycle].down_task, or [lifecycle.domains] cleanup");
}
return Err(e);
} Prevention
- Pair every up task with a down task in project templates
- Configure [lifecycle].down_task explicitly rather than relying on conventions
- Verify teardown works with a smoke test after adding lifecycle config
When it happens
Trigger: Running the down lifecycle command when flow.toml has no 'down' task, no [lifecycle].down_task, and either no [lifecycle.domains] section or run_domains_down performed no action.
Common situations: Project defines up tasks but never wired teardown; down task renamed without updating down_task; [lifecycle.domains] configured but its engine produced no runnable cleanup; editing the wrong flow.toml.
Related errors
- No lifecycle up task found. Define task 'up' or 'dev', or se
- lifecycle task '{}' not found
- invalid lifecycle.domains.engine '{}': expected 'docker' or
- lifecycle.domains.aliases[].host is required
- lifecycle.domains.aliases[].target is required
AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01).
Data as JSON: /api/errors/02844ce5546ebf16.
Report an issue: GitHub.