gleam-lang/gleam · error

== should be a valid range

Error message

== {version} should be a valid range

What it means

When a package was already provided by the same source, the resolver constructs a version constraint "== {version}" via hexpm::version::Range::new and unwraps it. It panics only if the stored package version string is not a syntactically valid version, since "== " + a valid semver is always a valid range.

Solutions

  1. Fix the malformed version string in manifest.toml or delete build/packages.toml to regenerate it
  2. Run `gleam deps download` after removing the build directory to rebuild the cache from Hex
  3. Restore manifest.toml from version control or regenerate it with `gleam add <package>`
  4. If the version genuinely is valid but rejected, report a hexpm/gleam version-parsing bug

Example fix

// before: corrupt entry in manifest.toml
{ name = "gleam_stdlib", version = "" }
// after
{ name = "gleam_stdlib", version = "0.38.0" }
Defensive patterns

Strategy: validation

Validate before calling

// Validate versions in manifest.toml are strict semver before resolving
fn valid_semver(v: &str) -> bool {
    v.split('.').count() == 3 && v.split('.').all(|p| p.parse::<u64>().is_ok())
}

Prevention

When it happens

Trigger: Re-resolving dependencies where manifest.toml or build/packages.toml contains a package version string that hexpm's parser rejects (corrupt, empty, or non-semver version).

Common situations: Hand-edited or corrupted manifest.toml/package cache files; truncation of files during a crash; a dependency source writing malformed versions.

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 gleam-lang/gleam@15b07c7830 (2026-09-14). Data as JSON: /api/errors/fb46ed02f156bcf0. Report an issue: GitHub.

Appendix: source

Thrown at compiler-cli/src/dependencies.rs:1514

    // Return early if a package cycle is detected
    if parents.contains(&package_name) {
        let mut last_cycle = parents
            .split(|p| p == &package_name)
            .next_back()
            .unwrap_or_default()
            .to_vec();
        last_cycle.push(package_name);
        return Err(Error::PackageCycle {
            packages: last_cycle,
        });
    }
    // Check that we do not have a cached version of this package already
    match provided.get(&package_name) {
        Some(package) if package.source == package_source => {
            // This package has already been provided from this source, return the version
            let version = hexpm::version::Range::new(format!("== {}", package.version))
                .expect("== {version} should be a valid range");
            return Ok(version);
        }
        Some(package) => {
            // This package has already been provided from a different source which conflicts
            return Err(Error::ProvidedDependencyConflict {
                package: package_name.into(),
                source_1: package_source.to_toml(),
                source_2: package.source.to_toml(),
            });
        }
        None => (),
    }
    // Load the package
    let config = crate::config::read(package_path.join("gleam.toml"))?;
    // Check that we are loading the correct project
    if config.name != package_name {
        return Err(Error::WrongDependencyProvided {
            expected: package_name.into(),

View on GitHub (pinned to 15b07c7830)