jdx/mise · error
brew-cask: : dependency cycle detected
Error message
brew-cask:{}: dependency cycle detected What it means
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.
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
Defensive patterns
Strategy: validation
Validate before calling
fn has_cycle(adj: &std::collections::HashMap<String, Vec<String>>, node: &str, path: &mut Vec<String>) -> bool {
if path.iter().any(|n| n == node) { return true; }
path.push(node.to_string());
let cyclic = adj.get(node).into_iter().flatten().any(|d| has_cycle(adj, d, path));
path.pop();
cyclic
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- brew-cask: : conflicts with installed cask
- brew-cask: : dependency cycle detected
- brew-cask: : Homebrew owns this cask; remove it with…
- brew-cask: : Homebrew took ownership of this cask while…
- brew-cask: requested token
AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22).
Data as JSON: /api/errors/2b44893c2de501f5.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/packages/brew/cask.rs:430
opts: &InstallOpts,
pr: Option<&dyn SingleReport>,
manager_options: &ManagerPackageOptions,
) -> Result<String> {
self.install_one_with_ancestors(req, opts, pr, &BTreeSet::new(), manager_options)
.await
}
async fn install_one_with_ancestors(
&self,
req: &PackageRequest,
opts: &InstallOpts,
pr: Option<&dyn SingleReport>,
ancestors: &BTreeSet<String>,
manager_options: &ManagerPackageOptions,
) -> Result<String> {
let cask = fetch_cask(req).await?;
if ancestors.contains(&cask.token) {
bail!("brew-cask:{}: dependency cycle detected", cask.token);
}
let mut ancestors = ancestors.clone();
ancestors.insert(cask.token.clone());
let artifacts = cask_artifacts(&cask)?;
validate_platform_support(&cask, &artifacts)?;
if homebrew_metadata_present(&cask.token) {
bail!(
"brew-cask:{}: Homebrew owns this cask; remove it with Homebrew before installing it with mise",
cask.token
);
}
let installed_version = installed_cask_version(&cask, &artifacts)?;
if let Some(version) = installed_version.as_ref()
&& (cask.auto_updates || version == &cask.version)
{
info!("brew-cask:{}: already installed", cask.token);
return Ok(version.clone());
}View on GitHub (pinned to 6f52dcdf99)