# Apache Airflow 3.3.1 — Apache Airflow 3.3.1 - Product: Apache Airflow (https://whatsnew.fyi/product/apache-airflow) - Vendor: Apache Software Foundation - Date: 2026-08-12 - Version: 3.3.1 - Original notes: https://github.com/apache/airflow/releases/tag/3.3.1 - Permalink: https://whatsnew.fyi/product/apache-airflow/releases/3.3.1 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'. --- - **changed** — Pandas 3 now exposes DataFrame as pandas.DataFrame instead of pandas.core.frame.DataFrame; Airflow registers both names so XComs written by either pandas version can be read by either version - **fixed** — Fix 2.x to 3.0+ upgrade failure when a custom Dag bundle is configured by running a one-shot backfill at startup to route affected Dags to the correct bundle - **changed** — Team scoped values of options registered as sensitive are now hidden in API responses and CLI output - **fixed** — Fix a 500 error when combining the last-run and any-run Dag state filters on the Dags list - **fixed** — Fix task log text selection being cleared while scrolling in the UI - **fixed** — Fix a translation key showing as raw text in the Clear Task dialog - **fixed** — Fail deferred task instances whose saved state can't be resumed instead of leaving them stuck - **fixed** — Fix task callbacks being skipped when TriggerDagRunOperator gets a 404 - **fixed** — Fix task state store rejecting keys that contain slashes - **fixed** — Fix the deadline_reference decorator's no-parentheses form - **fixed** — Fix Dag run duration stats crash on PostgreSQL 14+ - **fixed** — Deactivate legacy Dags with a NULL bundle_name during upgrade from 2.x to 3.x - **fixed** — Fix deadline alerts using an outdated Dag definition - **fixed** — Fix deadline alert crashes on dynamic or malformed intervals - **fixed** — Fix deadline alerts that have no fixed interval - **fixed** — Fix backfill permission checks running against the wrong backfill for some ID formats - **fixed** — Fix database lock contention and statement timeouts caused by slow asset listeners on large fan-outs - **fixed** — Fix errors loading a Dag callback whose module isn't importable on the current component - **fixed** — Reject reserved XCom serialization keys submitted as JSON string literals 📦 PyPI: https://pypi.org/project/apache-airflow/3.3.1/ 📚 Docs: https://airflow.apache.org/docs/apache-airflow/3.3.1/ 🛠 Release Notes: https://airflow.apache.org/docs/apache-airflow/3.3.1/release_notes.html 🐳 Docker Image: "docker pull apache/airflow:3.3.1" 🚏 Constraints: https://github.com/apache/airflow/tree/constraints-3.3.1 ##### Significant Changes ###### Pandas 3 changes how DataFrame XComs are stored and read back (#71169) pandas 3 exposes its public classes from the ``pandas`` namespace, so a DataFrame is qualified as ``pandas.DataFrame`` instead of ``pandas.core.frame.DataFrame``. XComs record that name alongside the serialized value, so the name written into the metadata database depends on the pandas version of the component that pushed the value. Airflow registers both names, and a DataFrame written by either pandas version can be read by either -- no configuration change is needed, and existing XComs stay readable. What you should do: * **Roll this Airflow version out to every component before pandas 3 reaches any of them** -- workers in particular. A component that predates this change cannot read a DataFrame XCom written under pandas 3, and fails the pull with: .. code-block:: text ImportError: pandas.DataFrame was not found in allow list for deserialization imports. To allow it, add it to allowed_deserialization_classes in the configuration The message points at configuration, but the allow list is not the cause and changing it does not help. The rows are not corrupt: they become readable again as soon as the reader is upgraded. * **Treat a downgrade as a one-way door for those XComs.** Rolling back to an Airflow version without this change strands any DataFrame XCom written while on pandas 3, with the same error, until you roll forward again. * **Review Dags that inspect the ``dtypes`` of a pulled DataFrame.** The pandas version of the *reader* determines what a pulled DataFrame looks like, not the version that wrote it. Under pandas 3, a column of strings comes back as ``str`` rather than ``object``, and its missing values come back as ``nan`` rather than ``None``. Values are unchanged, but downstream code that branches on ``dtype == "object"``, checks cells with ``is None``, or compares against a reference frame with ``DataFrame.equals()`` can behave differently after the upgrade. ###### Fix 2.x to 3.0+ upgrade failure when a custom Dag bundle is configured (#70994) The ``0082_3_1_0_make_bundle_name_not_nullable`` migration assigned every legacy row ``bundle_name='dags-folder'``, so triggering a DagRun raised ``Requested bundle 'dags-folder' is not configured.`` on any deployment that uses a bundle other than the default ``dags-folder``. ``DagFileProcessorManager`` now runs a one-shot, best-effort backfill at startup that routes each affected Dag to the correct bundle based on its file path; unmatched Dags self-heal on the next successful parse (or run ``airflow dags reserialize`` to force it immediately). ###### Team scoped values of options registered as sensitive are now hidden (#71099) Configuration options are registered as sensitive under their base section, so until now only the base spelling of an option was masked. A team scoped override -- set in a ``[=
]`` config file section, or through an ``AIRFLOW_____
__`` environment variable -- was not recognized as the same option and was returned in full. Sensitivity is now decided after resolving the team scoped spelling back to the base option, so a team scoped value is masked exactly as the base value already was. **Behaviour changes:** - ``AirflowConfigParser.as_dict(display_sensitive=False)``, ``GET /config``, ``GET /config/section/{section}/option/{option}`` and ``airflow config list`` now return ``< hidden >`` for a team scoped value of an option registered as sensitive. Deployments th _[Truncated at 4000 characters — full notes: https://github.com/apache/airflow/releases/tag/3.3.1]_