{"record":{"id":"2b44893c2de501f5","repo":"jdx/mise","slug":"brew-cask-dependency-cycle-detected","errorCode":null,"errorMessage":"brew-cask:{}: dependency cycle detected","messagePattern":"brew-cask:(.+?): dependency cycle detected","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask.rs","lineNumber":430,"sourceCode":"        opts: &InstallOpts,\n        pr: Option<&dyn SingleReport>,\n        manager_options: &ManagerPackageOptions,\n    ) -> Result<String> {\n        self.install_one_with_ancestors(req, opts, pr, &BTreeSet::new(), manager_options)\n            .await\n    }\n\n    async fn install_one_with_ancestors(\n        &self,\n        req: &PackageRequest,\n        opts: &InstallOpts,\n        pr: Option<&dyn SingleReport>,\n        ancestors: &BTreeSet<String>,\n        manager_options: &ManagerPackageOptions,\n    ) -> Result<String> {\n        let cask = fetch_cask(req).await?;\n        if ancestors.contains(&cask.token) {\n            bail!(\"brew-cask:{}: dependency cycle detected\", cask.token);\n        }\n        let mut ancestors = ancestors.clone();\n        ancestors.insert(cask.token.clone());\n        let artifacts = cask_artifacts(&cask)?;\n        validate_platform_support(&cask, &artifacts)?;\n        if homebrew_metadata_present(&cask.token) {\n            bail!(\n                \"brew-cask:{}: Homebrew owns this cask; remove it with Homebrew before installing it with mise\",\n                cask.token\n            );\n        }\n        let installed_version = installed_cask_version(&cask, &artifacts)?;\n        if let Some(version) = installed_version.as_ref()\n            && (cask.auto_updates || version == &cask.version)\n        {\n            info!(\"brew-cask:{}: already installed\", cask.token);\n            return Ok(version.clone());\n        }","sourceCodeStart":412,"sourceCodeEnd":448,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/src/system/packages/brew/cask.rs#L412-L448","documentation":"install_one_with_ancestors (src/system/packages/brew/cask.rs:430) walks a cask's dependency closure carrying the set of ancestor tokens. If the cask currently being resolved (by its API token field) is already present in `ancestors`, the recursion would never terminate, so mise aborts with a cycle error naming that token before any staging or copying.","triggerScenarios":"A tapped cask whose dependency closure revisits itself: cask A depends on cask B and B back on A, or a tap's api/cask/<token>.json declares a `token` value that collides with an ancestor because the tap re-uses or renames tokens across cask files.","commonSituations":"Third-party taps with hand-written cask JSON containing mutually-referencing casks; taps where two casks share the same token under different filenames; stale cached metadata after an upstream cask rename mid-install.","solutions":["Clear cached brew metadata (mise cache for system-brew) so fresh cask JSON is fetched, in case stale tokens created a phantom cycle","Inspect the involved casks' depends_on stanzas in the tap's api/*.json and report/fix the cycle upstream","If you maintain the tap, remove or break the cyclic dependency stanza","Install the cask with the Homebrew CLI as a stopgap, since brew's resolver may tolerate the graph mise refuses"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"fn has_cycle(adj: &std::collections::HashMap<String, Vec<String>>, node: &str, path: &mut Vec<String>) -> bool {\n    if path.iter().any(|n| n == node) { return true; }\n    path.push(node.to_string());\n    let cyclic = adj.get(node).into_iter().flatten().any(|d| has_cycle(adj, d, path));\n    path.pop();\n    cyclic\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate tapped cask dependency stanzas for cycles before adding a tap to configs","Clear cached cask metadata after upstream renames so stale tokens cannot fake a cycle","Report cyclic taps upstream — brew tolerating the graph does not make it valid"],"tags":["brew-cask","dependency-cycle","homebrew","graph"],"backgroundTag":"dependency-cycle-detected","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}