dbt-labs/dbt-core · error · anyhow

expected integer after `{lane_str}.`, got {number:?} in {sem

Error message

expected integer after `{lane_str}.`, got {number:?} in {semver:?}

What it means

For pre-release versions (X.Y.Z-lane.N), parse_release_version accepts only lanes alpha, beta, rc, preview, dev, and requires a non-empty integer after the lane's dot. This bail fires when the number portion after the lane is empty or contains non-digit characters.

Source

Thrown at crates/dbt-ci/src/release_version.rs:77

        bail!("expected X.Y.Z, got {base:?} in {semver:?}");
    }
    let Some(pre) = pre else {
        return Ok(ParsedReleaseVersion {
            base,
            prerelease: None,
        });
    };
    let (lane_str, number) = pre
        .split_once('.')
        .ok_or_else(|| anyhow!("expected `<lane>.N` after `-`, got {pre:?} in {semver:?}"))?;
    let lane = PreReleaseLane::parse(lane_str).ok_or_else(|| {
        anyhow!(
            "unsupported pre-release lane {lane_str:?} in {semver:?}; \
             accepted: alpha, beta, rc, preview, dev"
        )
    })?;
    if number.is_empty() || !number.chars().all(|c| c.is_ascii_digit()) {
        bail!("expected integer after `{lane_str}.`, got {number:?} in {semver:?}");
    }
    Ok(ParsedReleaseVersion {
        base,
        prerelease: Some((lane, number)),
    })
}

pub(crate) fn validate_release_version(semver: &str) -> Result<()> {
    parse_release_version(semver).map(|_| ())
}

pub(crate) fn semver_to_pep440(semver: &str) -> Result<String> {
    parse_release_version(semver).map(|p| p.to_pep440())
}

#[cfg(test)]
mod tests {
    use super::*;

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Make the prerelease number a single non-negative integer, e.g. "1.2.3-rc.1".
  2. Ensure the lane is one of alpha, beta, rc, preview, dev (a different lane produces the preceding anyhow error).
  3. Normalize your version-generation tool to emit single-integer prerelease suffixes.

Example fix

// before
parse_release_version("1.2.3-rc.1.2")?;
// after
parse_release_version("1.2.3-rc.2")?; // collapse to single integer
Defensive patterns

Strategy: validation

Validate before calling

fn validate_prerelease(v: &str) -> Result<(), String> {
    if let Some((_, pre)) = v.split_once('-') {
        let mut it = pre.splitn(2, '.');
        let lane = it.next().unwrap_or("");
        if !matches!(lane, "alpha"|"beta"|"rc"|"preview"|"dev") {
            return Err(format!("unsupported lane {lane:?}"));
        }
        match it.next() {
            Some(n) if !n.is_empty() && n.chars().all(|c| c.is_ascii_digit()) => Ok(()),
            other => Err(format!("prerelease number must be an integer, got {other:?}")),
        }
    } else { Ok(()) }
}

Try / catch

parse_release_version(v).map_err(|e| {
    eprintln!("invalid prerelease in {v:?}: {e}; use e.g. 1.2.3-rc.1");
    e
})?;

Prevention

When it happens

Trigger: Calling parse_release_version with a prerelease like "1.2.3-alpha.", "1.2.3-beta.x", "1.2.3-rc.01a", or "1.2.3-rc.1.2" where the segment after 'rc.' is not a pure integer.

Common situations: Using SemVer dot-separated prerelease identifiers (e.g. -rc.1.2 or -alpha.beta) that this stricter scheme doesn't accept, typos in manually set versions, or versions generated by tools emitting multi-part prerelease numbers.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07). Data as JSON: /api/errors/c16a81739fab2068. Report an issue: GitHub.