Refresh outdated dependencies flagged on the release branch
Clears the backend and frontend outdated-dependency reports from the release branch's check-outdated-dependencies run (run 33216120758), ordered easiest-first so the load-bearing bumps are reviewable on their own.
Every backend candidate in that report was verified to be older than the 7-day exclude-newer window before being taken, so none of them are freshly-published churn.
#7037 has merged, so this is now just the pins. The outdated-check tooling was split out per review and landed separately; this branch was rebased onto the main that carries it, so the script, its tests and the workflow rewrite are no longer in this diff — only the dependency bumps and the [tool.check-outdated-deps] entries that go with them.
Type of change
- Breaking change (fix or feature that would cause existing functionality to not work as expected) — the Bun minimum moves to 1.4.0; see below
- Bug fix (non-breaking change which fixes an issue)
Commits
Refresh locked dependency versions and widen the wrapt bound | uv lock --upgrade, starlette-admin 1.0 compat, wrapt <2.4 + stub workarounds, and two spent exclude-newer exemptions dropped |
Narrow redis response types and stop orphaning a redis state manager | correct under redis-py 7.x and 8.x both; groundwork plus a genuine fixture leak |
Bump frontend dependency pins and the bundled Bun to 1.4.0 | the frontend pins, the docs app's es-toolkit pin dropped, and the one breaking piece |
update docs/app dependency pins (@masenf) | the regenerated docs/app/reflex.lock |
Record the new dependency holds in the outdated-check config | the ignore-list additions, in #7037's style |
Bun 1.4.0 — the one breaking piece
MIN_VERSION has to move with VERSION. Bun 1.4 creates new lockfiles at lockfileVersion: 2, and 1.3.11 cannot parse a v2 lockfile at all; under --frozen-lockfile, the Reflex default, the install fails outright rather than degrading. Left at 1.3.0, the "bun already installed" fast path in install_bun would keep preferring a system 1.3.x over the pinned 1.4.0, and a project initialized under 1.4 would then break on a lockfile bun cannot read. Verified that with the minimum raised it declines a system 1.3.11 on PATH and installs the pinned 1.4.0.
The blast radius is narrower than "any 1.4 install breaks 1.3.x", and the warning text says so. Measured against both binaries:
bun 1.3.11 install -> lockfileVersion: 1
bun 1.4.0 add (existing v1) -> lockfileVersion: 1 (preserved)
bun 1.3.11 --frozen-lockfile on that lock -> OK
bun 1.4.0 install, no prior lock -> lockfileVersion: 2
An existing v1 lockfile stays v1 under 1.4 even across dependency changes, so already-initialized projects are unaffected; only a lockfile generated from scratch is v2. The regenerated docs/app lock is itself evidence — it carries Bun 1.4's new configVersion field while staying at lockfileVersion: 1.
The redis 8 attempt, and why it was backed out
I originally widened redis >=6.4,<8.0 → <9.0. That is reverted. redis-py 8 hangs three redis-backed tests on Python 3.10 and 3.11, and one is not a test artifact: test_app.py::test_initialize_with_state hangs in the test body awaiting app.state_manager.get_state(...), parked in the event-loop selector. The other two hang in async-fixture and loop teardown.
A/B on one machine, nothing else running, against a flushed redis:
py3.11 + redis-py 7.4.1 → 0 hangs, 120s
py3.11 + redis-py 8.1.0 → 3 hangs (60s pytest-timeout each), 300s
In CI this presented as the unit-tests workflow being cancelled rather than failed — the redis step sat ~26 min on ubuntu 3.10/3.11 until the 30-min job timeout, while 3.12–3.14 finished it in 1–2 min. Because the conclusion is cancelled, it reads as "nothing failed" on the checks API and in the check-suite webhook, which is how it initially escaped my notice.
Tracked in #7026, which carries the full diagnosis: all three hanging tests, the A/B above, the reproduction recipe (note --timeout-method=signal is required — with thread the async hangs never get named), and the checklist ending in widening the bound and closing #6764. #6764 stays open as the request and links to #7026 as its blocker.
Two things are deliberately kept, since both are correct under 7.x and 8.x and pyright is clean on either: the response-type narrowing in istate/manager/redis.py and utils/token_manager.py, and the tests/units/conftest.py fix for an orphaned StateManagerRedis whose _lock_task blocked event-loop teardown (StateManager.create() ran before branching on the fixture param, so a live redis manager was built and discarded unclosed for the in_process/disk params). The leak is worth fixing on its own merits, but to be clear it did not resolve the redis-8 hangs.
Held back, with issues filed
Each entry in frontend_held / backend_held names its blocker:
- tailwindcss / @tailwindcss/postcss (#7022) — I initially bumped these, which was wrong: the note on
Constants.VERSIONholds them at 4.3.0 because 4.3.1+ scans the git-ignored.webtree and collapses the docs prod build at scale, and I bumped straight past it. Reverted. 4.3.2/4.3.3 do not lift the hold — 4.3.1's tailwindlabs/tailwindcss#20214 ("scan explicitly referenced@sourcedirectories even when ignored by git") is the cause and is deliberate upstream behavior. My own validation could not have caught this: a small app builds fine on 4.3.3, and the failure is specifically a docs-scale collapse. - plotly.js 4.x (#7002) — removes
scattermapbox/choroplethmapbox/densitymapbox, the mapbox subplot, andmapboxAccessToken, which is whatPlotlyMapboxis built on.plotly.js-localesis held with it and listed explicitly: same repo, same pin, same blocker. - react-moment 2.x (#7003) — moves global config into a
settingsprop, restructures the props, dropsfilter, and adds amoment-duration-formatpeer dep. - redis 8.x (#7026, requested in #6764) — above.
- pydantic-core and pyee — exact-pinned by pydantic and playwright, so they can only move when the parent does.
pyright and ruff stay in *_pinned rather than *_held: they are pinned by policy, not blocked on anything, so reaching latest never means their entry is removable. That distinction is why #7037 has two keys.
Follow-ups
- #7024 — done, closed.
docs/app/reflex.lockneeded regenerating for the new pins; @masenf did it in the cherry-picked commit here. I verified the regenerated lock against every pin in this PR and they all match, with the deliberately-held ones still held andes-toolkitnow transitive-only. - #7023 — open. Whether a below-minimum custom or
REFLEX_USE_SYSTEM_BUNBun should hard-fail rather than warn. The default path is already correct; the residual case is an explicit opt-in whose warning-only behavior is asserted by an existing test. This PR only makes the warning name the lockfile consequence.
Testing
uv run pytest tests/unitswithREFLEX_REDIS_URLset — 8158 passed, 5 skipped, 0 failed.uv run pyright reflex tests— 0 errors.uv run ruff check ./ruff format --check .— clean.uv run python scripts/check_min_deps.py reflex— pass.scripts/make_pyi.pyleavespyi_hashes.jsonunchanged.uv lock --checkclean.- Frontend pins validated by a clean production export of an app exercising the bumped components: Reflex installs Bun 1.4.0 to its own path, resolves every new pin, and a second export round-trips the lockfile through a frozen install and rebuilds.
- Bun lockfile-version behavior measured directly against 1.3.11 and 1.4.0, as tabulated above.
On the rebase
The old history was 20 commits with three merges from main and a lot of self-cancelling churn (redis widened then backed out, tailwind bumped then reverted, the plotly ignore anchored then replaced by the script). Replaying that meant 32 commits conflicting from the second one, mostly resolving to "delete", so I rebuilt it as the five commits above instead. Verified equivalence rather than assuming it: the set of files changed relative to the base is identical to the old branch's, none lost and none extra, and all but two byte-identical — the two that differ are pyproject.toml and reflex/istate/proxy.py, both because main moved them. @masenf's docs-lock commit is cherry-picked so its authorship is preserved rather than folded into mine.
Still expected to report
The frontend job will still flag the reflex-enterprise-owned packages — @mantine/core, @xyflow/react, ag-charts-enterprise, ag-charts-react, react-colorful, rehype-sanitize. Those pins live in other repos, so I left them visible rather than adding them to frontend_pinned; ag-charts in particular looks like it belongs next to the existing ag-grid* entry, but that felt like your call rather than mine to bury.
🤖 Generated with Claude Code