{"record":{"id":"86f3b205c90f8d60","repo":"jdx/mise","slug":"infinitive-loop-detected-all-tasks-are-finished-b","errorCode":null,"errorMessage":"Infinitive loop detected, all tasks are finished but the graph isn't empty {0} {1:#?}","messagePattern":"Infinitive loop detected, all tasks are finished but the graph isn't empty (.+?) (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/task/deps.rs","lineNumber":373,"sourceCode":"        for task in leaves {\n            let key = task_key(&task);\n\n            if self.sent.insert(key.clone()) {\n                trace!(\"Scheduling task {0}\", task.name);\n                if let Err(e) = self.tx.send(Some(task)) {\n                    trace!(\"Error sending task: {e:?}\");\n                    self.sent.remove(&key);\n                }\n            }\n        }\n\n        if self.is_empty() {\n            trace!(\"All tasks finished\");\n            if let Err(e) = self.tx.send(None) {\n                trace!(\"Error closing task stream: {e:?}\");\n            }\n        } else if leaves_is_empty && self.sent.len() == self.removed.len() {\n            panic!(\n                \"Infinitive loop detected, all tasks are finished but the graph isn't empty {0} {1:#?}\",\n                self.all().map(|t| t.name.clone()).join(\", \"),\n                self.graph\n            )\n        }\n    }\n\n    /// listened to by `mise run` which gets a stream of tasks to run\n    pub fn subscribe(&mut self) -> mpsc::UnboundedReceiver<Option<Task>> {\n        let (tx, rx) = mpsc::unbounded_channel();\n        self.tx = tx;\n        self.emit_leaves();\n        rx\n    }\n\n    pub fn is_empty(&self) -> bool {\n        self.graph.node_count() == 0\n    }","sourceCodeStart":355,"sourceCodeEnd":391,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/task/deps.rs#L355-L391","documentation":"A Windows-only panic (expect) inside ToolVersion::runtime_path at src/toolset/tool_version.rs:266. For non-locked tool requests with a runtime pathname, mise looks up installs_path/<runtime-name>; on Windows a runtime symlink may be a file whose content is the target. If that file is a runtime symlink (is_runtime_symlink), its target resolves (file::resolve_symlink), parent.join(target) is a directory (line 263 guard), but absolutize() then fails to canonicalize that existing directory, expect panics and takes down the process.","triggerScenarios":"On Windows only: resolving runtime_path() (used by shims/exec to pick the active runtime dir) when the runtime-name entry is a file-based symlink shim, its recorded target points to an existing directory, and canonicalization of that directory fails — classic causes are paths exceeding MAX_PATH with long paths disabled, junction/symlink chains Windows cannot finalize, or ACLs denying traversal on a path component.","commonSituations":"Same class as the install_path panic: long nested profile paths with LongPathsEnabled off; runtime shim files left over after moving MISE_DATA_DIR or the installs tree; targets on network drives with flaky resolution; interrupted installs leaving a shim file whose target exists but is itself a dangling junction.","solutions":["Delete the runtime shim file (e.g. ~/.local/share/mise/installs/<tool>/<runtime-name>, a plain file) and rerun mise so it recreates a consistent symlink","Uninstall and reinstall the affected tool version to rebuild both install and runtime links atomically","Enable LongPathsEnabled (HKLM\\SYSTEM\\CurrentControlSet\\Control\\FileSystem) or move MISE_DATA_DIR to a short root (C:\\mise) to avoid MAX_PATH","Run `mise doctor` to confirm the installs tree layout, and verify the shim file's stored target with `Get-Content` before deleting","Update mise — later versions replace this expect with a propagated Result"],"exampleFix":"# before: panic at src/toolset/tool_version.rs:266\n# message: failed to absolutize path\nmise x python@3.12 -- python -V   # crashes while resolving runtime path\n\n# after: remove the file-based runtime symlink shim and let mise rebuild it\nRemove-Item \"$env:USERPROFILE\\.local\\share\\mise\\installs\\python\\3.12\" -Force   # plain shim file\nmise install python@3.12\nmise x python@3.12 -- python -V","handlingStrategy":"validation","validationCode":"// Rust callers on Windows: validate a file-based runtime symlink shim end-to-end\nfn usable_runtime_path(shim: &Path) -> Option<PathBuf> {\n    let target = PathBuf::from(std::fs::read_to_string(shim).ok()?);\n    let joined = shim.parent()?.join(target);\n    let canon = std::fs::canonicalize(&joined).ok()?;\n    canon.is_dir().then_some(canon)\n}","typeGuard":null,"tryCatchPattern":"Panic via expect() — not catchable as an error. Pre-validate the shim chain (read shim file -> join parent -> canonicalize -> is_dir) and treat failure as 'runtime symlink broken: delete shim and rerun mise install', optionally wrapping in catch_unwind at the process boundary.","preventionTips":["Enable LongPathsEnabled or shorten the installs root so canonicalization never hits MAX_PATH limits","After any mise upgrade or data-dir move, run `mise install` once to reconcile runtime symlink shims before scripting against them","On Windows servers with junction-heavy layouts, prefer real directory symlinks (enable Developer Mode / run elevated) over file-based shims"],"tags":["windows","path","canonicalize","panic","runtime-symlinks","symlinks"],"backgroundTag":"windows-path-canonicalization-failed","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}