{"record":{"id":"5a928da20b6f0530","repo":"jdx/mise","slug":"brew-cask-homebrew-took-ownership-of-this-cask","errorCode":null,"errorMessage":"brew-cask:{}: Homebrew took ownership of this cask while installation was pending","messagePattern":"brew-cask:(.+?): Homebrew took ownership of this cask while installation was pending","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask.rs","lineNumber":466,"sourceCode":"            for completion in &artifacts.completions {\n                miseprintln!(\n                    \"install {} completion {}\",\n                    completion.shell.name(),\n                    completion.source\n                );\n            }\n            for generated in &artifacts.generated_completions {\n                miseprintln!(\"generate completions from {}\", generated.executable);\n            }\n            return Ok(cask.version);\n        }\n        prefix::bootstrap(false)?;\n        let stage = fetch_and_stage(&cask, pr).await?;\n        let _caskroom_lock = lock_caskroom()?;\n        recover_flight_backups()?;\n        if homebrew_metadata_present(&cask.token) {\n            file::remove_all(&stage)?;\n            bail!(\n                \"brew-cask:{}: Homebrew took ownership of this cask while installation was pending\",\n                cask.token\n            );\n        }\n        if installed_cask_version(&cask, &artifacts)?.as_deref() == Some(cask.version.as_str()) {\n            file::remove_all(stage)?;\n            return Ok(cask.version);\n        }\n        let previous_binaries = previous_binary_targets(&cask)?;\n        let previous_fonts = previous_font_targets(&cask)?;\n        let previous_completions = previous_completion_targets(&cask)?;\n        let previous_flight_symlinks = previous_flight_symlink_targets(&cask)?;\n        let previous_flight_directories = previous_flight_directory_targets(&cask)?;\n        let previous_generic = previous_generic_targets(&cask)?;\n        let caskroom_token = caskroom_token_dir(&cask.token);\n        let caskroom = caskroom_version_dir(&cask.token, &cask.version);\n        let tmp_caskroom = caskroom_tmp_dir(&cask);\n        file::remove_all(&tmp_caskroom)?;","sourceCodeStart":448,"sourceCodeEnd":484,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/packages/brew/cask.rs#L448-L484","documentation":"mise re-checks Homebrew ownership at the last moment: after downloading and staging the cask payload (under the caskroom lock), it looks again for the `.metadata` marker. If it appeared since the first check, a concurrent `brew install --cask` claimed the cask mid-flight; mise deletes its staged payload and aborts rather than clobber brew's install — a TOCTOU guard.","triggerScenarios":"Running mise install/bootstrap for a cask while another process (brew CLI, another mise invocation, a CI step) installs the same cask; the marker appears between mise's pre-check and the post-staging re-check.","commonSituations":"Bootstrap scripts racing brew one-liners in dotfiles; parallel CI steps installing the same GUI tool; two mise processes started concurrently.","solutions":["Let the other installation finish, verify with `brew list --cask`, then re-run the mise command — mise will detect the cask as installed","Serialize installs: never run brew and mise cask installs concurrently for the same token"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Right before retrying, confirm whether the concurrent brew install finished:\nfn cask_installed_by_homebrew(token: &str) -> bool {\n    std::path::Path::new(&caskroom(token)).join(\".metadata\").symlink_metadata().is_ok()\n}","typeGuard":null,"tryCatchPattern":"Catch the 'took ownership while installation was pending' bail, wait for any concurrent brew process to exit, then re-run the mise install — the idempotent path will then report already-installed or proceed cleanly.","preventionTips":["Don't run brew install --cask and mise bootstrap concurrently for the same token","In CI, sequence GUI-app installs instead of parallelizing them"],"tags":["homebrew","cask","race-condition","toctou","mise"],"backgroundTag":"concurrent-package-manager-modification","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}