{"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":377,"sourceCode":"        &self,\n        req: &PackageRequest,\n        opts: &InstallOpts,\n        pr: Option<&dyn SingleReport>,\n    ) -> Result<String> {\n        self.install_one_with_ancestors(req, opts, pr, &BTreeSet::new())\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    ) -> 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        if installed_cask_version(&cask, &artifacts)?.as_deref() == Some(cask.version.as_str()) {\n            info!(\"brew-cask:{}: already installed\", cask.token);\n            return Ok(cask.version);\n        }\n        for conflict in &cask.conflicts_with.cask {\n            if !installed_versions(conflict).is_empty() {\n                bail!(","sourceCodeStart":359,"sourceCodeEnd":395,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/packages/brew/cask.rs#L359-L395","documentation":"While installing a Homebrew cask, mise walks the dependency chain passing along the set of ancestor casks already being installed. If the cask about to be installed is already in that set, the chain loops and mise aborts with this cycle error instead of recursing forever or stack-overflowing.","triggerScenarios":"Installing a cask whose depends_on chain (as published in the tap's cask JSON) leads back to itself — e.g. cask A depends on cask B which depends on A, typically from a tap author editing dependency metadata incorrectly.","commonSituations":"Third-party taps with hand-written dependency metadata; renames that turned two casks into mutual dependents; stale cached tap data after an upstream restructure.","solutions":["Update/refresh the tap so fresh cask JSON is fetched (mise caches HTTP JSON; clear the cache if needed)","Inspect the cask JSON's depends_on fields and report the loop to the tap maintainer","Install the cask with the brew CLI until the tap is fixed"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before batch-installing casks, walk the declared dependency graph and reject cycles:\nfn has_cycle(start: &str, deps: &dyn Fn(&str) -> Vec<String>) -> bool {\n    fn visit(node: &str, stack: &mut Vec<String>, deps: &dyn Fn(&str) -> Vec<String>) -> bool {\n        if stack.iter().any(|n| n == node) { return true; }\n        stack.push(node.to_string());\n        let r = deps(node).iter().any(|next| visit(next, stack, deps));\n        stack.pop();\n        r\n    }\n    visit(start, &mut vec![], deps)\n}","typeGuard":null,"tryCatchPattern":"Catch \"dependency cycle detected\" per cask and skip/report that cask instead of failing the whole batch; cycles are metadata bugs, not transient states, so retrying unchanged will not help.","preventionTips":["Pin taps you control to reviewed revisions with sane depends_on metadata","When authoring taps, never let cask dependencies reference an ancestor"],"tags":["homebrew","cask","dependency-cycle","mise"],"backgroundTag":"dependency-cycle-detected","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}