You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by po...@apache.org on 2025/07/04 13:31:24 UTC
(airflow) branch main updated: Prevent FileNotFoundError in deserialize_value of XCom io provider to crash the scheduler (#52702)
This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new ad10a103f76 Prevent FileNotFoundError in deserialize_value of XCom io provider to crash the scheduler (#52702)
ad10a103f76 is described below
commit ad10a103f760d12993f5c1112f8960e9d3cb99b9
Author: David Blain <in...@dabla.be>
AuthorDate: Fri Jul 4 15:31:18 2025 +0200
Prevent FileNotFoundError in deserialize_value of XCom io provider to crash the scheduler (#52702)
* refactor: Prevent FileNotFoundError in deserialize_value of XCom backend provider to crash the scheduler
* refactor: Reformatted test_serialization_deserialization_basic
* refactor: Made import of ObjectStoragePath cross airflow version compatible
---------
Co-authored-by: David Blain <da...@infrabel.be>
---
.../airflow/providers/common/io/xcom/backend.py | 2 +-
.../io/tests/unit/common/io/xcom/test_backend.py | 37 ++++++++++++++++------
2 files changed, 29 insertions(+), 10 deletions(-)
diff --git a/providers/common/io/src/airflow/providers/common/io/xcom/backend.py b/providers/common/io/src/airflow/providers/common/io/xcom/backend.py
index 4dd868067b8..01211b706ad 100644
--- a/providers/common/io/src/airflow/providers/common/io/xcom/backend.py
+++ b/providers/common/io/src/airflow/providers/common/io/xcom/backend.py
@@ -173,7 +173,7 @@ class XComObjectStorageBackend(BaseXCom):
try:
with path.open(mode="rb", compression="infer") as f:
return json.load(f, cls=XComDecoder)
- except (TypeError, ValueError):
+ except (FileNotFoundError, TypeError, ValueError):
return data
@staticmethod
diff --git a/providers/common/io/tests/unit/common/io/xcom/test_backend.py b/providers/common/io/tests/unit/common/io/xcom/test_backend.py
index 08967ca32d2..f85a4cfa0c7 100644
--- a/providers/common/io/tests/unit/common/io/xcom/test_backend.py
+++ b/providers/common/io/tests/unit/common/io/xcom/test_backend.py
@@ -17,7 +17,7 @@
# under the License.
from __future__ import annotations
-from unittest.mock import MagicMock
+from unittest.mock import MagicMock, patch
import pytest
@@ -35,9 +35,11 @@ pytestmark = [pytest.mark.db_test]
if AIRFLOW_V_3_0_PLUS:
from airflow.models.xcom import XComModel
+ from airflow.sdk import ObjectStoragePath
from airflow.sdk.execution_time.comms import XComResult
from airflow.sdk.execution_time.xcom import resolve_xcom_backend
else:
+ from airflow.io.path import ObjectStoragePath
from airflow.models.xcom import BaseXCom, resolve_xcom_backend # type: ignore[no-redef]
@@ -373,6 +375,11 @@ class TestXComObjectStorageBackend:
@pytest.mark.parametrize(
"value, expected_value",
[
+ pytest.param(
+ "file://airflow/xcoms/non_existing_file.json",
+ "file://airflow/xcoms/non_existing_file.json",
+ id="str",
+ ),
pytest.param(1, 1, id="int"),
pytest.param(1.0, 1.0, id="float"),
pytest.param("string", "string", id="str"),
@@ -385,11 +392,23 @@ class TestXComObjectStorageBackend:
],
)
def test_serialization_deserialization_basic(self, value, expected_value):
- XCom = resolve_xcom_backend()
- airflow.models.xcom.XCom = XCom
-
- serialized_data = XCom.serialize_value(value)
- mock_xcom_ser = MagicMock(value=serialized_data)
- deserialized_data = XCom.deserialize_value(mock_xcom_ser)
-
- assert deserialized_data == expected_value
+ def conditional_side_effect(data) -> ObjectStoragePath:
+ if isinstance(data, str) and data.startswith("file://"):
+ return ObjectStoragePath(data)
+ return original_get_full_path(data)
+
+ original_get_full_path = XComObjectStorageBackend._get_full_path
+
+ with patch.object(
+ XComObjectStorageBackend,
+ "_get_full_path",
+ side_effect=conditional_side_effect,
+ ):
+ XCom = resolve_xcom_backend()
+ airflow.models.xcom.XCom = XCom
+
+ serialized_data = XCom.serialize_value(value)
+ mock_xcom_ser = MagicMock(value=serialized_data)
+ deserialized_data = XCom.deserialize_value(mock_xcom_ser)
+
+ assert deserialized_data == expected_value