jdx/mise · error

expected exactly one Hex OTP build record for {release_tag},

Error message

expected exactly one Hex OTP build record for {release_tag}, found {}

What it means

For Linux precompiled OTP, mise downloads builds.txt from builds.hex.pm for the arch/OS and expects exactly one line whose first whitespace-separated field is the release tag OTP-<version>. Zero matches means Bob has not published that version for your arch/OS (too new, too old, or skipped); multiple matches means duplicate records upstream. Fatal when erlang.compile=false; otherwise it becomes a fallback reason and OTP compiles from source.

Source

Thrown at src/plugins/core/erlang.rs:805

        lock_platforms
            .get(platform_key)
            .is_some_and(|pi| pi.install.as_deref() == Some("source"))
    } else {
        erlang_compile == Some(true)
    }
}

fn parse_hex_build_checksum(builds: &str, release_tag: &str) -> Result<String> {
    let matching = builds
        .lines()
        .filter_map(|line| {
            let parts = line.split_whitespace().collect::<Vec<_>>();
            (parts.first() == Some(&release_tag)).then_some(parts)
        })
        .collect::<Vec<_>>();

    if matching.len() != 1 {
        bail!(
            "expected exactly one Hex OTP build record for {release_tag}, found {}",
            matching.len()
        );
    }

    let checksum = matching[0]
        .get(3)
        .ok_or_else(|| eyre::eyre!("Hex OTP build record for {release_tag} has no checksum"))?;
    if !regex!(r"^[0-9a-f]{64}$").is_match(checksum) {
        bail!("invalid Hex OTP checksum for {release_tag}: {checksum}");
    }

    Ok(format!("sha256:{checksum}"))
}

#[cfg(any(linux, test))]
fn require_locked_precompiled_checksum(version: &str, checksum: Option<&str>) -> Result<String> {
    let checksum = checksum.ok_or_else(|| {

View on GitHub (pinned to 6f52dcdf99)

Solutions

  1. Pick a version that exists for your platform: check https://builds.hex.pm/builds/otp/amd64/ubuntu-24.04/builds.txt (substitute your arch/OS) and pin that
  2. If the version just released, wait a day or two for Bob builds, or temporarily `mise settings set erlang.compile true`
  3. Verify the version string with `mise ls-remote erlang` — typos produce the same 'found 0' result
  4. If the file genuinely shows duplicates, report to the hex-core Bob project and use compile=true meanwhile

Example fix

# before
$ mise use -p erlang@27.3   # not yet in builds.txt → found 0

# after — pick a published build (or compile)
$ mise use -p erlang@27.2
# or: mise settings set erlang.compile true && mise install erlang@27.3
Defensive patterns

Strategy: validation

Validate before calling

# confirm Bob published this OTP for your arch/OS before a compile=false install
VER=27.1; ARCH=amd64; OS=ubuntu-24.04
curl -fsSL "https://builds.hex.pm/builds/otp/$ARCH/$OS/builds.txt" | grep -q "^OTP-$VER " \
  && mise install erlang@$VER \
  || { echo "no Bob build for OTP-$VER on $ARCH/$OS — choosing compile or another version"; exit 1; }

Try / catch

if ! mise install erlang@27.1; then
  # precompiled record missing — either wait for Bob, or build from source
  mise settings set erlang.compile true && mise install erlang@27.1
fi

Prevention

When it happens

Trigger: `mise install erlang@<v>` with compile=false where <v> is a freshly released OTP patch not yet built by Bob for your os_ver (arm64 typically lags amd64), an old version whose builds were dropped, or a version typo; also `mise lock` with compile=false on the same conditions.

Common situations: Pinning a brand-new OTP within hours of release on an arm64/Ubuntu-24.04 runner; version strings copied from erlang.org announcements before Bob catches up; duplicated upstream records after hex.pm incidents.

Related errors


AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22). Data as JSON: /api/errors/eeb253758ed3b611. Report an issue: GitHub.