Lint Python job has been failing on main since 2026-08-18, so every PR inherits a red check
Summary
The Lint Python job has been failing on main continuously since at least 2026-08-18. Every other job in the CI workflow passes on the same runs. Because the job fails on main, every open pull request inherits a red Lint Python check that is unrelated to its own diff, so the gate currently gives no signal — a genuine new lint regression in a PR is indistinguishable from the standing failure.
Evidence
Six most recent CI runs on main, all failure:
| run | head | conclusion |
|---|---|---|
| 33998987269 | 0c38749 |
failure |
| — | fad7219 |
failure |
| — | 54fd8db |
failure |
| — | f71da3f |
failure |
| — | e418363 |
failure |
| — | c3181d9 |
failure |
Jobs on the newest of those (0c38749): Test Python Framework (ubuntu + windows) success, Test Tools (ubuntu + windows) success, Validate Agent Exports skipped, Lint Python failure.
The job log for run 33998987269 ends with Found 21 errors, in B023 and I001.
Reproduction
git clone --depth 1 https://github.com/aden-hive/hive.git
cd hive
uv sync --project core --group dev
uv run --project core ruff check core/
uv run --project core ruff check tools/
uv run --project core ruff format --check core/
uv run --project core ruff format --check tools/Measured on a clean checkout of 0c38749 with ruff 0.16.6:
| step | result |
|---|---|
ruff check core/ |
22 errors — 14 B023, 6 I001, 1 UP041, 1 F401 |
ruff check tools/ |
138 errors — all I001 |
ruff format --check core/ |
19 files would be reformatted |
ruff format --check tools/ |
50 files would be reformatted |
The CI run reports 21 rather than 22 for core/. core/pyproject.toml declares ruff>=0.14.14 with no upper bound, so the version CI resolves at run time drifts and the count moves with it. Pinning a compatible range would make this job reproducible regardless of what the fix turns out to be.
ruff check tools/ never runs in CI today: the two ruff check commands share one run: block, so the shell exits after core/ fails and the 138 tools/ findings are not currently visible in the log.
The findings
I001 (144 across core/ and tools/) and UP041 and F401 — 146 total, all auto-fixable. ruff check --fix resolves every one. The F401 is framework.config.HIVE_HOME imported but unused in core/framework/server/routes_config.py; the UP041 is an aliased timeout error in core/framework/agent_loop/agent_loop.py that TimeoutError now covers.
B023 (14, all in core/framework/server/routes_execution.py) — worth stating precisely: these are not a live bug. All fourteen sit in four closures defined inside the for idx, img in enumerate(image_content) loop:
| closure | defined | invoked |
|---|---|---|
_inspect_pdf |
359 | await asyncio.to_thread(...) at 387 |
_parse_csv |
473 | 506 |
_read_text_attachment |
541 | 558 |
_probe_dims |
632 | 636 |
Each is awaited inside the same iteration that defines it, so the late-binding hazard B023 describes never actually fires — no closure outlives the iteration whose values it reads. The rule is correctly identifying the pattern; the current code is safe. Binding the captured names as default arguments silences it without any behaviour change.
Suggested fix
Two parts, mechanically separable:
ruff check --fix core/ tools/for the 146 auto-fixable findings, plusruff format core/ tools/for the 69 files.- Default-argument binding on the four closures above for the 14
B023.
I have this applied and verified locally against 0c38749: ruff check core/ and ruff format --check core/ both pass, with python -m py_compile clean on every touched file. The B023 change is 20 changed lines in routes_execution.py; the largest single file is routes_config.py at 89, nearly all of it ruff format reflow, since several files are wrapped near 88 columns while core/pyproject.toml sets line-length = 150.
Happy to open a PR for this. Following the contribution policy in #472 I am raising it as an issue first rather than opening one unprompted — if a maintainer wants it and assigns accordingly, I will send it. It is also easy to split: the auto-fixable half and the format half are independent of the B023 half, so this can land as one PR or three, whichever is easier to review.
One choice belongs to the maintainers rather than to me: whether tools/ should be linted at the same strictness as core/. If not, a per-file-ignores entry or dropping tools/ from the job would resolve 138 of the 160 findings without touching those files at all.
Source: aden-hive/hive