This is an automated email from the ASF dual-hosted git repository.

potiuk pushed a commit to branch v3-2-test
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/v3-2-test by this push:
     new f48dc4eccc6 [v3-2-test] fix: handle PermissionError in init_log_folder 
for mounted filesystems (#63878) (#66733)
f48dc4eccc6 is described below

commit f48dc4eccc6b10f7ffd11b3470f60e5d70facf9e
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Tue May 12 05:10:37 2026 +0200

    [v3-2-test] fix: handle PermissionError in init_log_folder for mounted 
filesystems (#63878) (#66733)
    
    * fix: handle PermissionError in init_log_folder for mounted filesystems
    
    * fix: narrow OSError to PermissionError and add init_log_folder regression 
test
    
    * fix: remove redundant try/except in configure_logging and clean up test
    
    * fix: broaden to OSError, rewrite test without caplog, add core 
newsfragment
    (cherry picked from commit 3ccf468a2ad3f4c4fae43907d5fd607c2027a047)
    
    Co-authored-by: Pranay Kumar Karvi <[email protected]>
    Co-authored-by: Jarek Potiuk <[email protected]>
---
 airflow-core/newsfragments/63878.bugfix.rst            |  1 +
 shared/logging/src/airflow_shared/logging/structlog.py | 12 +++++++++---
 shared/logging/tests/logging/test_structlog.py         | 11 ++++++++++-
 3 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/airflow-core/newsfragments/63878.bugfix.rst 
b/airflow-core/newsfragments/63878.bugfix.rst
new file mode 100644
index 00000000000..f85875f7433
--- /dev/null
+++ b/airflow-core/newsfragments/63878.bugfix.rst
@@ -0,0 +1 @@
+Fixed ``airflow`` CLI commands (including ``airflow db migrate``) crashing 
with ``PermissionError`` on startup when ``base_log_folder`` is configured to a 
path on a mounted filesystem (e.g. NFS) whose parent directories the Airflow 
user cannot create.
diff --git a/shared/logging/src/airflow_shared/logging/structlog.py 
b/shared/logging/src/airflow_shared/logging/structlog.py
index d82ac60526f..7dddafe3b0a 100644
--- a/shared/logging/src/airflow_shared/logging/structlog.py
+++ b/shared/logging/src/airflow_shared/logging/structlog.py
@@ -756,9 +756,15 @@ def init_log_folder(directory: str | os.PathLike[str], 
new_folder_permissions: i
     user.
     """
     directory = _PatchedPath(directory)
-    for parent in reversed(_PatchedPath(directory).parents):
-        parent.mkdir(mode=new_folder_permissions, exist_ok=True)
-    directory.mkdir(mode=new_folder_permissions, exist_ok=True)
+    try:
+        directory.mkdir(mode=new_folder_permissions, parents=True, 
exist_ok=True)
+    except OSError as e:
+        log.warning(
+            "Could not create log folder %s: %s. "
+            "Airflow will continue but logging to this directory may fail.",
+            directory,
+            e,
+        )
 
 
 def init_log_file(
diff --git a/shared/logging/tests/logging/test_structlog.py 
b/shared/logging/tests/logging/test_structlog.py
index 8904aa19326..5b5514b6864 100644
--- a/shared/logging/tests/logging/test_structlog.py
+++ b/shared/logging/tests/logging/test_structlog.py
@@ -25,6 +25,7 @@ import os
 import sys
 import textwrap
 from datetime import datetime, timezone
+from pathlib import Path
 from unittest import mock
 
 import pytest
@@ -35,7 +36,7 @@ from structlog.processors import CallsiteParameter
 from airflow_shared.logging import structlog as structlog_module
 from airflow_shared.logging.structlog import configure_logging
 
-# We don't want to use the caplog fixture in this test, as the main purpose of 
this file is to capture the
+# We avoid the caplog fixture for most tests here; the main purpose of this 
file is to capture the
 # _rendered_ output of the tests to make sure it is correct.
 
 PY_3_11 = sys.version_info >= (3, 11)
@@ -512,6 +513,14 @@ def 
test_excepthook_passes_keyboard_interrupt_to_original():
         sys.excepthook = original
 
 
+def test_init_log_folder_does_not_raise_on_permission_error():
+    from airflow_shared.logging.structlog import init_log_folder
+
+    with mock.patch.object(Path, "mkdir", side_effect=PermissionError("not 
allowed")):
+        # Must not raise — CLI commands like `airflow db migrate` rely on this.
+        init_log_folder("/tmp/blocked", 0o775)
+
+
 class TestWarningsInterceptor:
     @pytest.fixture(autouse=True)
     def reset(self):

Reply via email to