Prefect 3.7.1 Release Notes - Worker Channel and Orchestration Fixes

   |   3 minute read   |   Using 628 words

PrefectHQ shipped Prefect 3.7.1 on May 16, 2026, a point release that ships the first batch of worker channel infrastructure and clears out a stack of orchestration, concurrency, and result data bugs. Anyone running self hosted workers or pinning Python 3.13 should read this one carefully.

The full release notes and downloads are on the GitHub release page. The internal codename for the release is “Don’t touch that dial!”.

Worker channel groundwork

The largest chunk of new code in 3.7.1 is the worker channel pipeline. The release lands the contract and the first client, both authored by the team:

  • Worker channel protocol contract in #21859
  • Worker channel client with REST fallback in #21885
  • Worker cleanup executor in #21895
  • Worker work pool snapshot handling in #21898
  • cancelling_timeout_teardown.v1 cleanup handler in #21911

The shape is a typed protocol between worker and API, plus a client that falls back to the existing REST path when the channel is not available. Existing deployments are not forced to opt in yet, but the cleanup executor and the cancelling_timeout_teardown.v1 handler are already wired up so cancelled runs get torn down predictably instead of hanging in a half cancelled state.

Orchestration, concurrency, and result data fixes

The bug fix list is short on cosmetic items and heavy on correctness:

  • Flow run suspension at orchestration boundaries was broken in some paths. Fix in #21875.
  • Concurrency lease renewal could starve under load. The renewal now runs on a dedicated thread. See #21925.
  • Subflows could be duplicated when a process was re executed against the same flow_run_id. Patched in #21951.
  • COMPLETED to COMPLETED transitions that would discard result data are now rejected, see #21956.
  • .get() calls against arbitrary State.data in the result data loss rules are now guarded against non dict payloads in #21967.
  • The last_adhoc_pull timestamp in the runner now uses tz aware now("UTC") to stay consistent with the rest of the code base, fixed in #21961.

If any of these felt like flaky behaviour in 3.7.0, this is the upgrade that quiets them down.

CLI, templating, and default result storage

The release ships a few ergonomics changes that affect day to day work:

  • New deployment_name logging variable, useful when you correlate logs by deployment rather than by flow run id. PR #21804.
  • CLI now infers the logs page size from the API response instead of hard coding it. PR #21711.
  • A new CLI command for default result storage lands in #21771, with matching documentation in #21774. Server side default result storage is explicitly marked as beta in #21877, so treat it as such.
  • A Pydantic aware tojson template filter is added in #21861. Models serialize via the Pydantic path instead of the stock JSON one.
  • Default result storage is now cleared when its backing block is deleted, see #21862.

Python 3.13 and internal module moves

Two changes worth calling out for operators on newer Python:

  • DateTime is now strictly tz aware on Python 3.13 and above. Naive datetimes will be rejected. PR #21952.
  • A round of low and medium risk private modules moved under _internal. See #21879, #21881, and #21880. If your code reached into private paths in prefect for _result_records or utilities/_engine, those imports need updating.

The UI side gets a couple of small fixes too: flow run log downloads from the Prefect UI in #21718, and a trailing slash preserved when redirecting to the V2 UI in #21912.

Upgrade notes

  • If you depend on prefect-github, the extra floor is now >=0.4.2. Bumped in #21946.
  • On Python 3.13, audit any code paths that pass naive datetimes into Prefect APIs. They will now be rejected.
  • If you imported anything under prefect.* that started with an underscore, expect the import path to have moved under _internal/.

Where to get it



denis256 at denis256.dev