From 9d152faafca4ba71835439b98bacbd86ce4aa6f7 Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Sat, 11 Jul 2026 11:54:40 -0400 Subject: [PATCH 1/2] ci: add pins.json consistency check, bump ROCm index to 7.1 pins.json is consumed only by the Invoke Launcher (fetched at the release tag) to pick the torch wheel index for legacy installs. Nothing in-repo references it, so it silently drifted from pyproject.toml: its Linux ROCm index stayed at rocm6.3 after the torch-rocm index moved to rocm7.1, causing the launcher to install ROCm 6.3 wheels (#9328, launcher#131). - Add scripts/check_pins.py, which fails if any torchIndexUrl entry in pins.json differs from the matching [[tool.uv.index]] URL in pyproject.toml. - Run it from the uv-lock-checks workflow, triggered by changes to any of pyproject.toml, uv.lock, pins.json, or the check script. - Bump pins.json rocm index to rocm7.1 (matches #9337) so the check passes. - Bump the workflow's uv from 0.6.10 to 0.11.28: uv.lock is already lock format revision 3, which 0.6.x cannot parse. Co-Authored-By: Claude Fable 5 --- .github/workflows/uv-lock-checks.yml | 17 ++++++-- pins.json | 2 +- scripts/check_pins.py | 60 ++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 scripts/check_pins.py diff --git a/.github/workflows/uv-lock-checks.yml b/.github/workflows/uv-lock-checks.yml index d57163165fb..a9ba203fc4e 100644 --- a/.github/workflows/uv-lock-checks.yml +++ b/.github/workflows/uv-lock-checks.yml @@ -1,6 +1,8 @@ -# Check the `uv` lockfile for consistency with `pyproject.toml`. +# Check the `uv` lockfile and `pins.json` for consistency with `pyproject.toml`. # -# If this check fails, you should run `uv lock` to update the lockfile. +# If the lockfile check fails, you should run `uv lock` to update the lockfile. +# If the pins check fails, update the torch index URLs in `pins.json` to match +# the `[[tool.uv.index]]` entries in `pyproject.toml` (see scripts/check_pins.py). name: 'uv lock checks' @@ -54,15 +56,24 @@ jobs: uvlock-pyprojecttoml: - 'pyproject.toml' - 'uv.lock' + - 'pins.json' + - 'scripts/check_pins.py' - name: setup uv if: ${{ steps.changed-files.outputs.uvlock-pyprojecttoml_any_changed == 'true' || inputs.always_run == true }} uses: astral-sh/setup-uv@v8.1.0 with: - version: '0.6.10' + # Keep this at or above the uv version used to generate uv.lock (revision 3 lock + # format requires a modern uv; 0.6.x cannot parse it). + version: '0.11.28' enable-cache: true - name: check lockfile if: ${{ steps.changed-files.outputs.uvlock-pyprojecttoml_any_changed == 'true' || inputs.always_run == true }} run: uv lock --locked # this will exit with 1 if the lockfile is not consistent with pyproject.toml shell: bash + + - name: check pins.json + if: ${{ steps.changed-files.outputs.uvlock-pyprojecttoml_any_changed == 'true' || inputs.always_run == true }} + run: python3 scripts/check_pins.py # pins.json is consumed by the launcher; keep its torch index URLs in sync with pyproject.toml + shell: bash diff --git a/pins.json b/pins.json index 122e6c8e0ec..699c21b563f 100644 --- a/pins.json +++ b/pins.json @@ -6,7 +6,7 @@ }, "linux": { "cpu": "https://download.pytorch.org/whl/cpu", - "rocm": "https://download.pytorch.org/whl/rocm6.3", + "rocm": "https://download.pytorch.org/whl/rocm7.1", "cuda": "https://download.pytorch.org/whl/cu128" }, "darwin": {} diff --git a/scripts/check_pins.py b/scripts/check_pins.py new file mode 100644 index 00000000000..7a296e3d195 --- /dev/null +++ b/scripts/check_pins.py @@ -0,0 +1,60 @@ +"""Check that pins.json is consistent with pyproject.toml. + +``pins.json`` is not used anywhere in this repo — it is fetched (at the release +tag) by the Invoke Launcher (https://github.com/invoke-ai/launcher), which uses +its ``torchIndexUrl`` entries to pick the torch wheel index for legacy +(pre-6.14.0) installs. Because nothing in-repo consumes it, it can silently +drift from the ``[[tool.uv.index]]`` URLs in pyproject.toml — which is exactly +what happened when ROCm moved from 6.3 to 7.1 (issue #9328). + +This script fails if any ``torchIndexUrl`` entry in pins.json differs from the +URL of the corresponding ``torch-`` index in pyproject.toml. + +Run from anywhere: python scripts/check_pins.py +""" + +import json +import sys +import tomllib +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parent.parent + + +def main() -> int: + pins = json.loads((REPO_ROOT / "pins.json").read_text()) + pyproject = tomllib.loads((REPO_ROOT / "pyproject.toml").read_text()) + + indexes = {i["name"]: i["url"] for i in pyproject["tool"]["uv"]["index"]} + + errors: list[str] = [] + + for platform, backends in pins["torchIndexUrl"].items(): + for backend, pinned_url in backends.items(): + index_name = f"torch-{backend}" + expected_url = indexes.get(index_name) + if expected_url is None: + errors.append( + f"pins.json torchIndexUrl.{platform}.{backend}: no [[tool.uv.index]] named '{index_name}' in pyproject.toml" + ) + elif pinned_url != expected_url: + errors.append( + f"pins.json torchIndexUrl.{platform}.{backend} is '{pinned_url}' but pyproject.toml index '{index_name}' is '{expected_url}'" + ) + + if errors: + print("pins.json is out of sync with pyproject.toml:", file=sys.stderr) + for error in errors: + print(f" - {error}", file=sys.stderr) + print( + "\nUpdate pins.json to match the [[tool.uv.index]] URLs in pyproject.toml (or vice versa).", + file=sys.stderr, + ) + return 1 + + print("pins.json is consistent with pyproject.toml") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) From 108c8362e3e98b0c736fec60becea33508e4ba2e Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Sat, 11 Jul 2026 11:54:51 -0400 Subject: [PATCH 2/2] fix: cap torch below 2.12 on linux/windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit torch 2.12.x+rocm7.1 breaks generation (#9328; 2.11 works, and 2.10 is what the rocm extra pins). The cap only matters for legacy (pre-6.14) launcher installs, which resolve the base range live against the pytorch wheel indexes instead of using uv.lock — with the range open to <3.0, AMD users could land on the broken 2.12.x. Lockfile-based installs are unaffected: uv.lock stays at 2.7.1 / 2.10.0+rocm7.1 (no locked versions changed, only the recorded specifier). Remove the cap once the 2.12 ROCm incompatibility is diagnosed. Co-Authored-By: Claude Fable 5 --- pyproject.toml | 4 +++- uv.lock | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index de665d621e3..ba880d70b93 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,9 @@ dependencies = [ # Loosely pinned, will respect requirement of `diffusers[torch]`. Split by platform: linux/win allow # >=2.10 so the rocm extra can use torch 2.10.0+rocm7.1, while macOS stays on 2.7.x — newer macOS torch # wheels exercise MPS on CI runners (no usable Metal GPU) and fail with MPS OOM. - "torch>=2.7.0,<3.0; sys_platform != 'darwin'", + # Capped <2.12: torch 2.12.x+rocm7.1 breaks generation (#9328), and legacy (pre-6.14) launcher + # installs resolve this range live against the pytorch wheel indexes rather than using uv.lock. + "torch>=2.7.0,<2.12; sys_platform != 'darwin'", "torch>=2.7.0,<2.8.0; sys_platform == 'darwin'", "torchsde", # diffusers needs this for SDE solvers, but it is not an explicit dep of diffusers "torchvision", diff --git a/uv.lock b/uv.lock index 6d1b0a462f8..aff88d7d410 100644 --- a/uv.lock +++ b/uv.lock @@ -1176,7 +1176,7 @@ requires-dist = [ { name = "sentencepiece", specifier = "==0.2.0" }, { name = "snakeviz", marker = "extra == 'dev'" }, { name = "spandrel" }, - { name = "torch", marker = "sys_platform != 'darwin'", specifier = ">=2.7.0,<3.0" }, + { name = "torch", marker = "sys_platform != 'darwin'", specifier = ">=2.7.0,<2.12" }, { name = "torch", marker = "sys_platform == 'darwin'", specifier = ">=2.7.0,<2.8.0" }, { name = "torch", marker = "sys_platform == 'linux' and extra == 'rocm'", specifier = "==2.10.0+rocm7.1", index = "https://download.pytorch.org/whl/rocm7.1", conflict = { package = "invokeai", extra = "rocm" } }, { name = "torch", marker = "extra == 'cpu'", specifier = "==2.7.1+cpu", index = "https://download.pytorch.org/whl/cpu", conflict = { package = "invokeai", extra = "cpu" } }, @@ -3710,10 +3710,10 @@ name = "torch" version = "2.7.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.12' and sys_platform == 'darwin'", - "python_full_version < '3.12' and sys_platform == 'darwin'", "(python_full_version >= '3.12' and platform_machine == 'x86_64' and sys_platform == 'linux') or (python_full_version >= '3.12' and sys_platform == 'win32')", "(python_full_version < '3.12' and platform_machine == 'x86_64' and sys_platform == 'linux') or (python_full_version < '3.12' and sys_platform == 'win32')", + "python_full_version >= '3.12' and sys_platform == 'darwin'", + "python_full_version < '3.12' and sys_platform == 'darwin'", ] dependencies = [ { name = "filelock", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra != 'extra-8-invokeai-cpu' and extra != 'extra-8-invokeai-cuda' and extra != 'extra-8-invokeai-rocm') or (sys_platform == 'darwin' and extra == 'extra-8-invokeai-rocm') or (sys_platform == 'darwin' and extra != 'extra-8-invokeai-cpu' and extra != 'extra-8-invokeai-cuda') or (sys_platform == 'win32' and extra != 'extra-8-invokeai-cpu' and extra != 'extra-8-invokeai-cuda' and extra != 'extra-8-invokeai-rocm') or (extra == 'extra-8-invokeai-cpu' and extra == 'extra-8-invokeai-cuda') or (extra == 'extra-8-invokeai-cpu' and extra == 'extra-8-invokeai-rocm') or (extra == 'extra-8-invokeai-cuda' and extra == 'extra-8-invokeai-rocm')" }, @@ -3862,10 +3862,10 @@ name = "torchvision" version = "0.22.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.12' and sys_platform == 'darwin'", - "python_full_version < '3.12' and sys_platform == 'darwin'", "(python_full_version >= '3.12' and platform_machine == 'x86_64' and sys_platform == 'linux') or (python_full_version >= '3.12' and sys_platform == 'win32')", "(python_full_version < '3.12' and platform_machine == 'x86_64' and sys_platform == 'linux') or (python_full_version < '3.12' and sys_platform == 'win32')", + "python_full_version >= '3.12' and sys_platform == 'darwin'", + "python_full_version < '3.12' and sys_platform == 'darwin'", ] dependencies = [ { name = "numpy", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra != 'extra-8-invokeai-cpu' and extra != 'extra-8-invokeai-cuda' and extra != 'extra-8-invokeai-rocm') or (sys_platform == 'darwin' and extra == 'extra-8-invokeai-rocm') or (sys_platform == 'darwin' and extra != 'extra-8-invokeai-cpu' and extra != 'extra-8-invokeai-cuda') or (sys_platform == 'win32' and extra != 'extra-8-invokeai-cpu' and extra != 'extra-8-invokeai-cuda' and extra != 'extra-8-invokeai-rocm') or (extra == 'extra-8-invokeai-cpu' and extra == 'extra-8-invokeai-cuda') or (extra == 'extra-8-invokeai-cpu' and extra == 'extra-8-invokeai-rocm') or (extra == 'extra-8-invokeai-cuda' and extra == 'extra-8-invokeai-rocm')" },