{"record":{"id":"0bf4cfa753aef94e","repo":"jdx/mise","slug":"configured-notifications-came-from-managed-files","errorCode":null,"errorMessage":"configured notifications came from managed files","messagePattern":"configured notifications came from managed files","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cli/bootstrap.rs","lineNumber":1179,"sourceCode":"        let services_enabled = !skip.contains(&BootstrapPart::Services);\n        let notifications_configured =\n            managed_system_files\n                .as_ref()\n                .is_some_and(|(files, directories)| {\n                    files.iter().any(|file| !file.notify.is_empty())\n                        || directories\n                            .iter()\n                            .any(|directory| !directory.notify.is_empty())\n                });\n        let configured_services = if services_enabled || notifications_configured {\n            Some(system::services::prepare_requests_from_config(&config)?)\n        } else {\n            None\n        };\n        if notifications_configured {\n            let (files, directories) = managed_system_files\n                .as_ref()\n                .expect(\"configured notifications came from managed files\");\n            let services = configured_services\n                .as_ref()\n                .expect(\"configured notifications prepared services\");\n            system::services::validate_notifications(files, directories, services)?;\n        }\n        let mut managed_services =\n            services_enabled.then_some(configured_services.unwrap_or_default());\n        let mut managed_firewall = if skip.contains(&BootstrapPart::Firewall) {\n            None\n        } else {\n            system::firewall::prepare_request_from_config(&config)?\n        };\n        let mut managed_compose = if skip.contains(&BootstrapPart::Compose) {\n            None\n        } else {\n            Some(system::compose::prepare_requests_from_config(&config)?)\n        };\n        let dry_run_compose_actions = if self.dry_run","sourceCodeStart":1161,"sourceCodeEnd":1197,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/src/cli/bootstrap.rs#L1161-L1197","documentation":"Internal invariant while validating [bootstrap.files]/[bootstrap.directories] `notify` configuration. `notifications_configured` is itself derived from `managed_system_files` being Some and containing notify entries (src/cli/bootstrap.rs:1162-1170), so when it is true, `managed_system_files.as_ref()` at line 1177 must be Some. The expect documents that notifications only come from managed files and guards against future refactors that compute notifications from another source.","triggerScenarios":"Only reachable via a code change that sets notifications_configured independently of managed_system_files (or clears managed_system_files while notify config exists) — then `mise bootstrap` with notify entries panics at validate_notifications. No user flag combination reaches it: with the files part skipped, managed_system_files is None AND notifications_configured is false.","commonSituations":"Contributors adding a new notification source (e.g. service-level notify) without updating this branch; broken custom builds. Normal runs with --skip=files plus notify config do not trigger it because notifications_configured follows managed_system_files.","solutions":["If hit as a user: this is a bug in that mise build — update or pin a released version","Workaround: remove `notify` keys from [bootstrap.files]/[bootstrap.directories] entries, or run `mise bootstrap --skip=files`","As a contributor: derive notifications_configured and managed_system_files from the same source, or replace the expect with an explicit error naming the divergent source","Report with the panic backtrace at https://github.com/jdx/mise/issues"],"exampleFix":"// before: notifications computed from a new independent source\nlet notifications_configured = config_has_notify_anywhere(&config); // diverges from managed files\n\n// after: keep the single source of truth\nlet notifications_configured = managed_system_files.as_ref().is_some_and(|(files, dirs)| {\n    files.iter().any(|f| !f.notify.is_empty()) || dirs.iter().any(|d| !d.notify.is_empty())\n});","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep `notify` keys only on [bootstrap.files]/[bootstrap.directories] entries — the sole supported source","Use mise bootstrap --dry-run to validate notify wiring before real runs","Report invariant panics upstream with the full bootstrap config"],"tags":["bootstrap","invariant","panic","internal","notifications"],"backgroundTag":"internal-invariant-violation","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}