{"record":{"id":"8093fcb9691811b2","repo":"jdx/mise","slug":"bootstrap-compose-project-name-oneshot-service","errorCode":null,"errorMessage":"bootstrap compose project '{name}' oneshot services must also appear in services","messagePattern":"bootstrap compose project '(.+?)' oneshot services must also appear in services","errorType":"validation","errorClass":"eyre::Report","httpStatus":null,"severity":"error","filePath":"src/system/compose.rs","lineNumber":317,"sourceCode":"        {\n            bail!(\n                \"bootstrap compose project '{name}' down_volumes and down_images require state = \\\"absent\\\"\"\n            );\n        }\n        if config.state != ComposeState::Running && config.renew_anonymous_volumes {\n            bail!(\n                \"bootstrap compose project '{name}' renew_anonymous_volumes requires state = \\\"running\\\"\"\n            );\n        }\n        let explicit_dependencies = config\n            .depends_on\n            .iter()\n            .map(|dependency| parse_dependency(dependency))\n            .collect::<Result<Vec<_>>>()?;\n        let services = dedupe(config.services);\n        let oneshot: IndexSet<String> = dedupe(config.oneshot).into_iter().collect();\n        if !services.is_empty() && oneshot.iter().any(|service| !services.contains(service)) {\n            bail!(\n                \"bootstrap compose project '{name}' oneshot services must also appear in services\"\n            );\n        }\n        let files = resolve_paths(&config.project_dir, config.files);\n        let env_files = resolve_paths(&config.project_dir, config.env_files);\n        let path_dependencies = std::iter::once(ResourceId::new(\n            \"directory\",\n            config.project_dir.to_string_lossy(),\n        ))\n        .chain(\n            files\n                .iter()\n                .chain(&env_files)\n                .map(|path| ResourceId::new(\"file\", path.to_string_lossy())),\n        )\n        .collect::<IndexSet<_>>()\n        .into_iter()\n        .collect();","sourceCodeStart":299,"sourceCodeEnd":335,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/compose.rs#L299-L335","documentation":"`oneshot` marks services that should be run to completion (migrations, seeds) rather than kept running; mise launches them from the same service set as the normal `services` selection. `ComposeRequest::from_toml` therefore requires every oneshot entry to appear in `services` when an explicit `services` list is set.","triggerScenarios":"A compose table sets `services = [\"api\", \"worker\"]` and `oneshot = [\"migrate\"]` — `migrate` is not in `services`, so parsing bails. (When `services` is empty all configured services are implied, and the check is skipped.)","commonSituations":"Forgetting to add the migration/seed service to the selected services list; renaming a service in the compose file but only updating one of the two lists.","solutions":["Add the missing oneshot service to `services`: `services = [\"api\", \"worker\", \"migrate\"]`.","Or drop it from `oneshot` if it should not be converged by this project.","Cross-check both lists against `docker compose config --services` output for the project."],"exampleFix":"# before\n[bootstrap.compose.web]\nproject_dir = \"/srv/web\"\nservices = [\"api\", \"worker\"]\noneshot = [\"migrate\"]\n\n# after\n[bootstrap.compose.web]\nproject_dir = \"/srv/web\"\nservices = [\"api\", \"worker\", \"migrate\"]\noneshot = [\"migrate\"]","handlingStrategy":"validation","validationCode":"let services: std::collections::HashSet<&String> = cfg.services.iter().collect();\nfor one in &cfg.oneshot {\n    assert!(services.contains(one), \"oneshot service '{one}' missing from services\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Add every oneshot service to the services list in the same edit.","Cross-check services/oneshot against `docker compose config --services` when the compose file changes."],"tags":["mise","bootstrap","compose","config","oneshot","validation"],"backgroundTag":"config-validation-failed","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}