{"record":{"id":"c8dbb02ef2d0d6ef","repo":"jdx/mise","slug":"executor-must-be-initialized-before-running-tasks","errorCode":null,"errorMessage":"executor must be initialized before running tasks","messagePattern":"executor must be initialized before running tasks","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cli/run.rs","lineNumber":1376,"sourceCode":"                .executor\n                .as_ref()\n                .map(|e| e.is_interrupted())\n                .unwrap_or(false)\n    }\n\n    fn mark_interrupted(&self) {\n        if let Some(executor) = &self.executor {\n            executor.mark_interrupted();\n        }\n    }\n\n    async fn run_task_sched(\n        &self,\n        ctx: TaskRunContext<'_>,\n    ) -> Result<crate::task::task_executor::TaskRunOutcome> {\n        self.executor\n            .as_ref()\n            .expect(\"executor must be initialized before running tasks\")\n            .run_task_sched(ctx)\n            .await\n    }\n\n    fn add_failed_task(&self, task: Task, status: Option<i32>) {\n        if let Some(executor) = &self.executor {\n            executor.add_failed_task(task, status);\n        }\n    }\n\n    fn validate_task(&self, task: &Task) -> Result<()> {\n        use crate::file;\n        use crate::ui;\n        if self.task_cache.enabled() && task.cache.as_ref().is_some_and(|cache| cache.enabled) {\n            Settings::get().ensure_experimental(\"task artifact caching\")?;\n        }\n        if task.rust_cache.as_ref().is_some_and(|cache| cache.enabled) {\n            deprecated_at!(","sourceCodeStart":1358,"sourceCodeEnd":1394,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/cli/run.rs#L1358-L1394","documentation":"`run_task_sched` forwards each scheduled task to the `TaskExecutor`, which `run` creates during setup. The `.expect()` panics if `self.executor` is `None`, meaning the scheduler is being driven without the initialization step that `run` performs. This is a programming-invariant guard, not a user-facing error.","triggerScenarios":"Invoking the scheduler callback `run_task_sched` from a code path that never called `setup_executor()`; constructing the runner struct manually in tests or new commands without initialization; an early-return bug in setup that still lets scheduling begin.","commonSituations":"Contributors adding a new subcommand that reuses the task scheduler but forgets the executor setup step; test harnesses constructing the runner directly.","solutions":["Run `MISE_DEBUG=1 mise <cmd>` and report the panic with the trace to the mise repository","Ensure your command flows through the normal `Run` command implementation rather than hand-building the runner","Call `setup_executor()` before any scheduling in custom code paths","Update to the latest mise version to rule out a fixed regression"],"exampleFix":"// before\nself.executor.as_ref().expect(\"executor must be initialized before running tasks\").run_task_sched(ctx).await\n// after\nlet executor = self.executor.as_ref()\n    .ok_or_else(|| eyre!(\"internal error: executor not initialized\"))?;\nexecutor.run_task_sched(ctx).await","handlingStrategy":"validation","validationCode":"// Before scripting around mise, verify the command works normally:\nmise run --dry-run <task> || echo \"scheduler path broken; update mise\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Drive task execution only through the public `mise run` CLI","In forked/patched builds, always call `setup_executor()` before scheduling","Pin a known-good mise version in CI"],"tags":["rust","panic","internal-invariant","task-runner"],"backgroundTag":"internal-invariant-violation","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}