{"record":{"id":"25614116e268aa55","repo":"jdx/mise","slug":"brew-cask-dependency-cycle-detected-256141","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/mod.rs","lineNumber":555,"sourceCode":"        self.install_one_with_ancestors(req, opts, pr, &BTreeSet::new(), manager_options, mode)\n            .await\n    }\n\n    /// Installs a cask while detecting dependency cycles and preserving ownership.\n    /// Dependencies use install mode. The requested cask's eligibility is checked\n    /// before staging and again under the installation lock before replacement.\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        mode: InstallMode,\n    ) -> Result<String> {\n        let cask = fetch_cask(req, !opts.dry_run).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        if let Some(version) = homebrew_installed_version(&cask.token)? {\n            info!(\n                \"brew-cask:{}: installed and managed by Homebrew; leaving unchanged\",\n                cask.token\n            );\n            return Ok(version);\n        }\n        let artifacts = cask_artifacts(&cask)?;\n        validate_platform_support(&cask, &artifacts)?;\n        let installed_version = mise_installed_cask_version(&cask)?;\n        if let Some(reason) =\n            installed_skip_reason(&cask, &artifacts, installed_version.as_deref(), mode)?\n        {\n            info!(\"brew-cask:{}: {reason}\", cask.token);\n            return Ok(reason.to_string());","sourceCodeStart":537,"sourceCodeEnd":573,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/packages/brew/cask/mod.rs#L537-L573","documentation":"While recursively installing a cask's dependency chain, Homebrew tracks ancestor cask tokens; if a cask appears in its own ancestor set the chain is cyclic and installation is aborted. This prevents infinite recursion when cask `depends_on cask:` declarations form a loop.","triggerScenarios":"install_one (or the recursive dependency walker) encounters a cask whose token is already present in the `ancestors` BTreeSet — e.g. cask A depends on B and B depends on A, or a self-dependency.","commonSituations":"Third-party taps with mis-declared `depends_on cask:` stanzas; newly edited casks introducing a cycle; users installing two casks whose dependency sets reference each other.","solutions":["Inspect the cask's `depends_on cask:` declarations to find the cycle","Fix the tap/cask by removing the erroneous dependency edge","Install the problematic cask directly if its dependency is spurious","Report the cycle to the tap maintainer if it's a third-party cask"],"exampleFix":"// before (cask B)\ndepends_on cask: \"a\"   # while cask A depends_on cask: \"b\"\n// after (cask B)\n# remove the circular depends_on line","handlingStrategy":"validation","validationCode":"fn cycle_check(token: &str, ancestors: &BTreeSet<String>) -> Result<()> {\n    if ancestors.contains(token) {\n        Err(format!(\"dependency cycle at {token}\"))\n    } else { Ok(()) }\n}","typeGuard":null,"tryCatchPattern":"match install_cask(req).await {\n    Err(e) if e.to_string().contains(\"dependency cycle detected\") => {\n        eprintln!(\"inspect depends_on cask: chain for {}\", req.name);\n        Err(e)\n    }\n    r => r,\n}","preventionTips":["Review `depends_on cask:` edges in tap for acyclicity before merging","Keep dependency graphs shallow in custom taps","Test cask installs in CI to surface cycles early"],"tags":["brew","cask","dependency-cycle","recursion"],"backgroundTag":"invalid-state-transition","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}