# Apache Airflow 3.2.2 — Apache Airflow 3.2.2 - Product: Apache Airflow (https://whatsnew.fyi/product/apache-airflow) - Vendor: Apache Software Foundation - Date: 2026-05-29 - Version: 3.2.2 - Original notes: https://github.com/apache/airflow/releases/tag/3.2.2 - Permalink: https://whatsnew.fyi/product/apache-airflow/releases/3.2.2 What's New is an index, not a publisher: every entry below links to the vendor's own release notes, which are the authoritative source. Entries are labelled where they are hand-curated sample data, pre-releases, or drawn from a secondary source such as a developer blog. Reuse: the summaries, labels and curation here are © What's New. Quote freely with attribution and a link back; wholesale republication of the corpus is not permitted — terms: https://whatsnew.fyi/terms. The vendors' own release notes remain their publishers'. --- - **security** — SMTP STARTTLS upgrade now validates the SMTP server's certificate against the system's trusted CA bundle by default instead of accepting any certificate - **changed** — REST API list endpoints switched from full-match *_pattern query parameters to index-friendly *_prefix_pattern parameters for search filters - **added** — Add per-search-bar "Match anywhere" toggle in the UI to allow users to switch between prefix-based and substring-based search - **fixed** — Fix triggerer race condition and deadlock that caused deferred tasks to stall indefinitely - **added** — Add triggerer subprocess watchdog with [triggerer] runner_health_check_threshold config option to detect hung triggers - **changed** — Tighten [core] allowed_deserialization_classes_regexp to require full-string matches using re.fullmatch() instead of re.match() - **changed** — Custom deadline reference classes must now be registered via the deadline_references attribute on AirflowPlugin - **fixed** — Fix Callback.handle_event triggerer crash when OpenTelemetry metrics receive dict typed tag values - **fixed** — Fix UI modulepreload hrefs to use the api-server static path - **fixed** — Correctly pre-allocate external_executor_id with multiple executors on PostgreSQL - **fixed** — Return raw import-error stacktrace when a DAG file has no registered DAG - **fixed** — Fix Expand/Collapse All functionality on XComs and Audit Log JSON cells in the UI - **fixed** — Load Monaco workers via a same-origin Blob shim in the UI - **fixed** — Show DAG name in browser tab title - **changed** — Require starlette>=1.0.1 for Host-header parsing fix and cadwyn>=6.1.1 for compatibility - **fixed** — Revoke JWT on /auth/logout regardless of auth manager logout URL - **fixed** — Fix deadlock in ti_update_state caused by FOR UPDATE locking dag_run 📦 PyPI: https://pypi.org/project/apache-airflow/3.2.2/ 📚 Docs: https://airflow.apache.org/docs/apache-airflow/3.2.2/ 🛠 Release Notes: https://airflow.apache.org/docs/apache-airflow/3.2.2/release_notes.html 🐳 Docker Image: "docker pull apache/airflow:3.2.2" 🚏 Constraints: https://github.com/apache/airflow/tree/constraints-3.2.2 ##### Significant Changes - The SMTP STARTTLS upgrade performed by ``airflow.utils.email.send_email`` now validates the SMTP server's certificate against the system's trusted CA bundle by default. Previously the ``starttls()`` call was made without an SSL context, so any certificate was accepted. Deployments that intentionally point Airflow at an SMTP server with a self-signed or otherwise non-validating certificate and need to preserve the previous behaviour must set ``email.ssl_context = "none"`` in ``airflow.cfg``. The ``"default"`` value (now also the default when the option is unset) uses :func:`ssl.create_default_context`. Previously this option applied only to the ``SMTP_SSL`` path; it now applies to the STARTTLS path as well. (#65346) - In #64963, the Airflow UI switched from full-match ``*_pattern`` REST API query parameters to the new index-friendly ``*_prefix_pattern`` parameters on list endpoints. This is a behavioral change for search-as-you-type filters in the UI: matches are prefix-based (``LIKE 'term%'`` via a range scan) instead of substring-based (``ILIKE '%term%'``), which means the database can use B-tree indexes and search stays fast on large deployments. The REST API itself keeps both forms: existing ``*_pattern`` parameters still behave exactly as before. In #66015, a per-search-bar "Match anywhere" toggle was added so users who relied on the previous substring behavior can opt back into it from the UI. Each search input and each text filter pill now has a small regex-icon toggle next to the value; flipping it on switches that input from ``*_prefix_pattern`` to ``*_pattern``. (#66015) - Fix triggerer race condition and deadlock that caused deferred tasks to stall indefinitely Triggers that call synchronous SDK methods (e.g. ``get_task_states`` used by ``safe_to_cancel`` in several Google provider operators) could crash the triggerer's internal subprocess. The triggerer would then continue to heartbeat normally — appearing healthy to the scheduler — while silently processing zero triggers, causing every deferred task to time out. This was first reported in issue #64620; a partial fix shipped in Airflow 3.2.1 (#64882) but introduced a new deadlock with the same visible symptom under load. Both issues are fixed by replacing the lock-based serialization with response multiplexing: each request now carries a unique ID and the response is routed back to the correct caller, so concurrent requests from trigger threads no longer contend or deadlock regardless of how many triggers are running or what SDK methods they call. **New: triggerer subprocess watchdog** Even with the race fixed, a trigger that blocks the event loop (e.g. by calling ``time.sleep()`` or performing blocking I/O directly in ``async def run()``) would previously leave the triggerer appearing healthy indefinitely. A new ``[triggerer] runner_health_check_threshold`` config option (default: 30 seconds) adds a watchdog: if the triggerer subprocess goes silent for longer than the threshold, the parent process stops updating the heartbeat so the scheduler can detect the hang and reassign triggers rather than waiting for them to individually time out. Set the option to ``0`` to disable the watchdog. (#66412) - Tighten ``[core] allowed_deserialization_classes_regexp`` to require full-string matches Patterns in ``[core] allowed_deserialization_classes_regexp`` are now matched against the entire classname using ``re.fullmatch()`` instead of ``re.match()``. Previously a pattern such as ``airflow\.models\.Variable`` admitte _[Truncated at 4000 characters — full notes: https://github.com/apache/airflow/releases/tag/3.2.2]_