{"record":{"id":"e75aa98195c708e8","repo":"jdx/mise","slug":"refusing-unsafe-change-to-bootstrap-compose-projec","errorCode":null,"errorMessage":"refusing unsafe change to bootstrap compose project '{}'; inspect `mise bootstrap plan`","messagePattern":"refusing unsafe change to bootstrap compose project '(.+?)'; inspect `mise bootstrap plan`","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/compose.rs","lineNumber":209,"sourceCode":"        .map(|request| request.plan_with_dependency_change(dependency_changed))\n        .collect()\n}\n\npub fn apply(requests: &[ComposeRequest], dry_run: bool, yes: bool) -> Result<()> {\n    apply_with_dry_run_actions(requests, &HashMap::new(), dry_run, yes)\n}\n\npub fn apply_with_dry_run_actions(\n    requests: &[ComposeRequest],\n    dry_run_actions: &HashMap<String, ResourceAction>,\n    dry_run: bool,\n    yes: bool,\n) -> Result<()> {\n    let mut changes = vec![];\n    for request in requests {\n        let action = apply_action(request, dry_run_actions, dry_run);\n        match action {\n            ResourceAction::Unknown => bail!(\n                \"refusing unsafe change to bootstrap compose project '{}'; inspect `mise bootstrap plan`\",\n                request.name\n            ),\n            ResourceAction::Noop => {}\n            ResourceAction::Create | ResourceAction::Update | ResourceAction::Remove => {\n                changes.push(request)\n            }\n        }\n    }\n    if changes.is_empty() {\n        info!(\"compose projects: already converged\");\n        return Ok(());\n    }\n    if dry_run {\n        for request in changes {\n            for argv in request.dry_run_action_argvs()? {\n                miseprintln!(\"would run {}\", shell_words::join(argv));\n            }","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/compose.rs#L191-L227","documentation":"`apply_with_dry_run_actions` reconciles each `[bootstrap.compose.<name>]` request against the actions recorded during dry-run/plan, refined by a fresh classification in `apply_action`. A project classified as `ResourceAction::Unknown` means mise cannot safely determine whether the deployed project matches the config, and it refuses to guess rather than risk tearing down or recreating a live project. The message points at `mise bootstrap plan` for inspection.","triggerScenarios":"Running apply when the dry-run/plan map has no usable entry for a project, or when live classification cannot decide (docker engine unreachable mid-run, `docker compose config` failing, state indeterminate) so `apply_action` falls back to Unknown.","commonSituations":"Applying right after a plan made on a different host or with the engine down; engine socket permissions differing under sudo vs the user; stale plan data after the compose file changed underneath the run.","solutions":["Run `mise bootstrap plan` (or `apply --dry-run`) and read the reported action for the named project — Unknown there shows classification itself failed.","Fix the classification blocker: ensure the docker engine is reachable (and reachable under sudo if `sudo = true`), compose v2 works, and `project_dir`/`files` resolve.","Re-run `mise bootstrap compose apply`; once every project classifies as Noop/Create/Update/Remove the refusal disappears."],"exampleFix":"# before\nmise bootstrap compose apply\n# error: refusing unsafe change to bootstrap compose project 'web'; ...\n\n# after\nmise bootstrap compose plan     # inspect why the project classifies as Unknown\n# fix engine/compose availability, then:\nmise bootstrap compose apply","handlingStrategy":"validation","validationCode":"// run the plan pass first and assert every project has a known action\nlet plans = compose::plans(&requests);\nfor plan in &plans {\n    assert!(\n        !matches!(plan.action, ResourceAction::Unknown),\n        \"project {} classifies as Unknown; fix engine/compose availability first\",\n        plan.id.value\n    );\n}\ncompose::apply_with_dry_run_actions(&requests, &dry_run_actions, dry_run, yes)?;","typeGuard":null,"tryCatchPattern":"match compose::apply_with_dry_run_actions(&reqs, &actions, dry_run, yes) {\n    Ok(()) => {}\n    Err(err) if err.to_string().contains(\"refusing unsafe change\") => {\n        // do NOT force past it: re-run `mise bootstrap compose plan`, fix why the named\n        // project classifies as Unknown (engine reachable? sudo context?), then retry.\n    }\n    Err(err) => return Err(err),\n}","preventionTips":["Always run `mise bootstrap compose plan` before apply in CI and fail on Unknown actions.","Keep engine access identical between plan and apply (same user/sudo, same DOCKER_HOST)."],"tags":["mise","bootstrap","compose","docker","plan-apply","safety-guard"],"backgroundTag":"plan-apply-mismatch","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}