AlexsJones/llmfit · error · ValueError

Invalid version: {version!r}

Error message

Invalid version: {version!r}

What it means

LlmfitMetadataHook.update() resolves the Python package version: the LLMFIT_VERSION environment variable wins, otherwise [workspace.package].version from the repo-root Cargo.toml. It must match ^\d+\.\d+\.\d+$ exactly (plain MAJOR.MINOR.PATCH); anything else aborts wheel metadata resolution with this ValueError, which fails uv build, uv sync, and pip builds of llmfit-python.

Source

Thrown at llmfit-python/hatch_build.py:74

    PLUGIN_NAME = "llmfit version, license and readme"

    def update(self, metadata: dict) -> None:
        """Populate dynamic metadata from the repository.

        ``version`` and ``license-expression`` come from ``Cargo.toml``,
        ``readme`` from the repository root.

        Version resolution order:

        1. ``LLMFIT_VERSION`` environment variable (e.g. ``0.9.8``).
        2. The ``version`` field in ``[workspace.package]`` from ``Cargo.toml``.
        """
        with (Path(self.root).parent / "Cargo.toml").open("rb") as f:
            workspace_package: dict[str, str] = tomli.load(f)["workspace"]["package"]
        version: str = os.environ.get("LLMFIT_VERSION") or workspace_package["version"]
        if not re.match(r"^\d+\.\d+\.\d+$", version):
            raise ValueError(f"Invalid version: {version!r}")
        metadata["version"] = version
        metadata["license-expression"] = workspace_package["license"]

        # The package README is the repository one. Hatchling refuses a
        # `readme = "../README.md"` path ("must be within the project
        # directory") but takes the contents verbatim, so read it here rather
        # than duplicating or symlinking the file.
        readme = Path(self.root).parent / "README.md"
        metadata["readme"] = {
            "content-type": "text/markdown",
            "text": readme.read_text(encoding="utf-8"),
        }


class LlmfitBinaryBuildHook(BuildHookInterface):
    """Hatchling build hook that injects the llmfit binary into each wheel."""

    PLUGIN_NAME = "llmfit binary"

View on GitHub (pinned to a9ac7ed91c)

Solutions

  1. Echo $LLMFIT_VERSION and strip anything beyond MAJOR.MINOR.PATCH (drop 'v', suffixes, whitespace) or unset it: `unset LLMFIT_VERSION`.
  2. If the version comes from Cargo.toml, set [workspace.package] version to a plain semver triplet and keep release identifiers elsewhere.
  3. In CI, normalize before export: LLMFIT_VERSION=$(git describe --tags | sed -E 's/^v?([0-9]+\.[0-9]+\.[0-9]+).*$/\1/').
  4. Verify with `python -c "import re,sys; print(bool(re.match(r'^\d+\.\d+\.\d+$', sys.argv[1])))" "$LLMFIT_VERSION"` before invoking the build.

Example fix

# before
export LLMFIT_VERSION="v0.9.8-rc.1"
uv build

# after
export LLMFIT_VERSION="0.9.8"
uv build
Defensive patterns

Strategy: validation

Validate before calling

import os, re

version = os.environ.get('LLMFIT_VERSION') or read_cargo_version()
if not re.match(r'^\d+\.\d+\.\d+$', version):
    version = re.search(r'\d+\.\d+\.\d+', version).group(0)  # normalize, or fail loudly
assert re.match(r'^\d+\.\d+\.\d+$', version), f'bad version {version!r}'

Try / catch

try:
    subprocess.run(['uv', 'build'], check=True, env=env)
except subprocess.CalledProcessError as e:
    if 'Invalid version:' in (e.stderr or ''):
        fix_and_retry_with_normalized_LLMFIT_VERSION()  # strip 'v', suffixes, whitespace
    raise

Prevention

When it happens

Trigger: Exporting LLMFIT_VERSION=0.9.8-rc.1 or 0.9.8+dev before building the wheel; bumping Cargo.toml's workspace version to a prerelease form like 0.10.0-rc.1; an LLMFIT_VERSION with a leading 'v' or trailing whitespace/newline from a CI step; an empty LLMFIT_VERSION string is falsy and falls through, but a malformed non-empty one always trips this.

Common situations: CI pipelines deriving LLMFIT_VERSION from a git tag (v1.2.3 keeps the 'v', 1.2.3-rc.1 keeps the suffix); release automation setting a pre-release identifier that Python allows but this strict regex forbids; a stale env var left in a shell from an earlier experiment.

Related errors


AI-assisted analysis of AlexsJones/llmfit@a9ac7ed91c (2026-08-16). Data as JSON: /api/errors/ae200507b967eafb. Report an issue: GitHub.