{"record":{"id":"2133611999bcdb1f","repo":"langflow-ai/langflow","slug":"could-not-read-lfx-version-from-src-lfx-pyproject","errorCode":null,"errorMessage":"Could not read lfx version from src/lfx/pyproject.toml","messagePattern":"Could not read lfx version from src/lfx/pyproject\\.toml","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"scripts/migrate/port_bundle.py","lineNumber":141,"sourceCode":"\n\ndef _current_lfx_floor() -> str:\n    \"\"\"Return the ``lfx`` dependency floor for a freshly-ported bundle.\n\n    Reads the workspace lfx version from ``src/lfx/pyproject.toml`` and pins\n    ``lfx>=X.Y.0.dev0,<(X+1).0.0`` -- floored at the current major.minor\n    line's first pre-release (the branch's own canonical ``X.Y.0.devN``\n    nightlies sort below a plain ``X.Y.0`` under PEP 440, so they must be\n    admitted by the floor), capped below the next lfx major.  Mirrors\n    ``lfx_floor_spec`` in ``scripts/ci/sync_bundle_lfx_pin.py`` (each script\n    is kept standalone, so keep the two in step); that script re-syncs every\n    existing bundle on ``make patch``.\n    \"\"\"\n    lfx_pyproject = (REPO_ROOT / \"src\" / \"lfx\" / \"pyproject.toml\").read_text(encoding=\"utf-8\")\n    match = re.search(r'^version = \"(\\d+)\\.(\\d+)\\.\\d+', lfx_pyproject, re.MULTILINE)\n    if not match:\n        msg = \"Could not read lfx version from src/lfx/pyproject.toml\"\n        raise ValueError(msg)\n    major, minor = int(match.group(1)), int(match.group(2))\n    return f\"lfx>={major}.{minor}.0.dev0,<{major + 1}.0.0\"\n\n\n# ---------------------------------------------------------------------------\n# Templates\n# ---------------------------------------------------------------------------\n\n\nPYPROJECT_TEMPLATE = \"\"\"\\\n[project]\nname = \"lfx-{bundle}\"\nversion = \"0.1.0\"\ndescription = \"{display_name} component(s) as a standalone Langflow Extension Bundle.\"\nreadme = \"README.md\"\nrequires-python = \">=3.10,<3.15\"\nlicense = {{ text = \"MIT\" }}\nauthors = [","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/scripts/migrate/port_bundle.py#L123-L159","documentation":"port_bundle.py computes the lfx dependency floor/cap for a new bundle (lfx>=X.Y.0.dev0,<(X+1).0.0) by regex-matching a static `version = \"<major>.<minor>.<patch>...\"` line in src/lfx/pyproject.toml. If the regex does not match — the version line is missing, dynamic, or formatted differently — it raises ValueError('Could not read lfx version from src/lfx/pyproject.toml'). Note: a completely missing file surfaces as FileNotFoundError first; this error specifically means the file was read but its version could not be parsed.","triggerScenarios":"Running port_bundle.py when src/lfx/pyproject.toml declares its version dynamically (e.g. `dynamic = [\"version\"]` with a hatch/setuptools plugin) or the version string starts with something the anchored regex `^version = \"(\\d+)\\.(\\d+)\\.\\d+` cannot match (prefixed letters, single quotes, or a build variable).","commonSituations":"Downstream forks that switched to dynamic versioning; a reformatting of pyproject.toml (whitespace inside the assignment is tolerated by the regex, but quotes style or `version=` without spaces on a multiline table is not); running the script from a repo state where the lfx package pyproject was refactored.","solutions":["Ensure src/lfx/pyproject.toml contains a static PEP 621 line like `version = \"1.8.0\"` at the start of a line (double quotes, three numeric segments).","If versioning must stay dynamic, temporarily resolve the version (e.g. `hatch version`) and write the static line before running the script, then revert.","Re-run `python scripts/migrate/port_bundle.py --bundle <name>` and confirm the generated bundle pyproject gets a sane lfx floor."],"exampleFix":"# before (src/lfx/pyproject.toml)\n[project]\nname = \"lfx\"\ndynamic = [\"version\"]\n\n# after\n[project]\nname = \"lfx\"\nversion = \"1.8.0\"","handlingStrategy":"try-catch","validationCode":"import re\nfrom pathlib import Path\n\nLFX_PYPROJECT = Path(\"src/lfx/pyproject.toml\")\n\ndef lfx_version_line_ok() -> bool:\n    text = LFX_PYPROJECT.read_text(encoding=\"utf-8\")\n    return re.search(r'^version = \"(\\d+)\\.(\\d+)\\.\\d+', text, re.MULTILINE) is not None","typeGuard":null,"tryCatchPattern":"try:\n    port_bundle.main([\"--bundle\", name, \"--apply\"])\nexcept ValueError as exc:\n    if \"Could not read lfx version\" in str(exc):\n        # fix src/lfx/pyproject.toml to a static PEP 621 version, then retry once\n        raise SystemExit(\"src/lfx/pyproject.toml needs a static version = \\\"X.Y.Z\\\" line\") from exc\n    raise","preventionTips":["Keep a static `version = \"X.Y.Z\"` line in src/lfx/pyproject.toml; avoid dynamic = [\"version\"] in this repo.","Note this script's floor logic is mirrored in scripts/ci/sync_bundle_lfx_pin.py — keep both in mind when changing versioning.","A missing file raises FileNotFoundError; this message means the file exists but the version line didn't parse."],"tags":["packaging","versioning","regex","migration"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}