jdx/mise · error · eyre::Report

tap '{tap}' must be in <owner>/<repo> format; supply an expl

Error message

tap '{tap}' must be in <owner>/<repo> format; supply an explicit URL for non-standard taps

What it means

When importing installed Homebrew formulae, taps absent from the config get a GitHub URL derived by strict convention: the tap must be exactly <owner>/<repo> with both parts non-empty, mapping to https://github.com/<owner>/homebrew-<repo>.git. Any other shape — single segment, three segments, empty parts — cannot be mapped and must be supplied explicitly.

Source

Thrown at src/system/packages/brew/maintenance.rs:91

    #[serde(default)]
    installed_on_request: Option<bool>,
    #[serde(default)]
    source: Option<ReceiptSource>,
}

#[derive(Debug, Default, Deserialize)]
struct ReceiptSource {
    #[serde(default)]
    tap: Option<String>,
}

pub fn default_tap_url(tap: &str) -> Result<String> {
    let mut parts = tap.split('/');
    match (parts.next(), parts.next(), parts.next()) {
        (Some(owner), Some(repo), None) if !owner.is_empty() && !repo.is_empty() => {
            Ok(format!("https://github.com/{owner}/homebrew-{repo}.git"))
        }
        _ => bail!(
            "tap '{tap}' must be in <owner>/<repo> format; supply an explicit URL for non-standard taps"
        ),
    }
}

pub fn linked_formulae(include_all: bool) -> Result<Vec<InstalledFormula>> {
    let opt = prefix::prefix().join("opt");
    let mut formulae = BTreeMap::new();
    for entry in file::ls(&opt)? {
        if !entry
            .symlink_metadata()
            .is_ok_and(|m| m.file_type().is_symlink())
        {
            continue;
        }
        let Some(name) = entry
            .file_name()
            .and_then(|f| f.to_str())

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Add an explicit URL for the tap in the target config: [bootstrap.brew.taps]."<tap>" = "https://git.example.com/group/homebrew-tap.git", then re-run import
  2. Rename the local tap to a proper <owner>/<repo> form so the GitHub convention applies
  3. Skip importing formulae from that tap (remove/untap it first) if it is not needed

Example fix

# before: tap 'internal-tools' fails URL derivation
# system import -> tap 'internal-tools' must be in <owner>/<repo> format

# after: supply the URL explicitly in the target config
[bootstrap.brew.taps]
"internal-tools" = "https://git.mycorp.com/dev/homebrew-internal-tools.git"
Defensive patterns

Strategy: validation

Validate before calling

// Validate tap shape before import; only <owner>/<repo> maps to a default URL.
fn tap_has_default_url(tap: &str) -> bool {
    let mut parts = tap.split('/');
    matches!((parts.next(), parts.next(), parts.next()),
        (Some(owner), Some(repo), None) if !owner.is_empty() && !repo.is_empty())
}

Type guard

fn is_standard_tap(tap: &str) -> bool {
    let mut p = tap.split('/');
    matches!((p.next(), p.next(), p.next()), (Some(o), Some(r), None) if !o.is_empty() && !r.is_empty())
}

Try / catch

// Supply explicit URLs for nonstandard taps instead of relying on the default:
let url = configured_taps
    .get(tap)
    .cloned()
    .map(Ok)
    .unwrap_or_else(|| default_tap_url(tap))
    .wrap_err_with(|| format!("add [bootstrap.brew.taps].\"{tap}\" = \"<git-url>\" to the target config"))?;

Prevention

When it happens

Trigger: system import (brew) -> InstalledFormula::tap_entry_with_urls -> default_tap_url(tap) when the tap is not a key in [bootstrap.brew.taps]. Fails for taps like 'mytap', 'team/internal/tools', or 'owner/' found in a formula's install receipt (Tab/ReceiptSource.tap).

Common situations: Machines using private or nonstandard tap names (no owner/repo shape); taps cloned from non-GitHub forges; receipts with malformed tap strings; importing after someone hand-created taps.

Related errors


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/6ceea377c8f807e7. Report an issue: GitHub.