Repository: sdv-dev/SDV

Issue:
SDV cannot be used on a readonly filesystem
### Environment Details
* SDV version: v1.21.0 (released May 16, 2025)

### Error Description
In SDV #2517, we intended to support SDV running on readonly filesystems. This issue was closed and made it out within the latest release on May 16, 2025 ([v1.21.0](https://github.com/sdv-dev/SDV/releases/tag/v1.21.0)).

However, it appears that there may still be some issues with readonly filesystems, as a user pointed out:

> This did not work. I got `NotADirectoryError: [Errno 20] Not a directory` I believe shouldn't the behavior not be creating any logs at all or care if it's a directory or not.

### Steps to reproduce
Install SDV on a readonly filesystem and try to use it.


Discussion:

Patch:
diff --git a/sdv/logging/logger.py b/sdv/logging/logger.py
index 415621b06..ccb5c4fba 100644
--- a/sdv/logging/logger.py
+++ b/sdv/logging/logger.py
@@ -73,6 +73,9 @@ def wrapper(*args, **kwargs):
             fallback_logger.warning('Falling back to NullHandler logger due to PermissionError.')
             return fallback_logger
 
+        except Exception:
+            return logging.getLogger(__name__)
+
     return wrapper
 
 
diff --git a/sdv/logging/utils.py b/sdv/logging/utils.py
index 83b043364..ac78ccbc5 100644
--- a/sdv/logging/utils.py
+++ b/sdv/logging/utils.py
@@ -24,12 +24,16 @@ def get_sdv_logger_config():
     except PermissionError:
         # No access to user's data.
         if os.access(config_path, os.W_OK):
-            store_path = config_path
+            store_path = config_path.parent
 
         else:
             # No access to python env
             return logger_conf
 
+    except OSError:
+        # Read only system
+        return logger_conf
+
     if (store_path / 'sdv_logger_config.yml').exists():
         config_path = store_path / 'sdv_logger_config.yml'
 


Test patch:
diff --git a/tests/unit/logging/test_logger.py b/tests/unit/logging/test_logger.py
index 84dc3ec37..5001a1b22 100644
--- a/tests/unit/logging/test_logger.py
+++ b/tests/unit/logging/test_logger.py
@@ -3,6 +3,8 @@
 import logging
 from unittest.mock import Mock, patch
 
+import pytest
+
 from sdv.logging.logger import CSVFormatter, get_sdv_logger
 
 
@@ -118,3 +120,28 @@ def test_get_sdv_logger_permission_error(mock_get_sdv_logger_config):
 
     # Assert
     assert isinstance(logger.handlers[0], logging.NullHandler)
+
+
+@pytest.mark.parametrize(
+    'side_effect',
+    [
+        NotADirectoryError,
+        OSError,
+        RuntimeError,
+        TypeError,
+        ValueError,
+        AttributeError,
+        PermissionError,
+    ],
+)
+def test_get_sdv_logger_with_exceptions(side_effect):
+    """Test fallback to a logger when logger config raises different exceptions."""
+    # Setup
+    get_sdv_logger.cache_clear()
+
+    with patch('sdv.logging.logger.get_sdv_logger_config', side_effect=side_effect):
+        # Run
+        logger = get_sdv_logger('test_logger_csv')
+
+        # Assert
+        assert isinstance(logger.handlers[0], logging.NullHandler)
diff --git a/tests/unit/logging/test_utils.py b/tests/unit/logging/test_utils.py
index a28393ffd..d14df8587 100644
--- a/tests/unit/logging/test_utils.py
+++ b/tests/unit/logging/test_utils.py
@@ -42,6 +42,18 @@ def test_get_sdv_logger_config():
     }
 
 
+@patch('sdv.logging.utils.platformdirs.user_data_dir', return_value='/mock/user/data')
+@patch('sdv.logging.utils.Path.mkdir', side_effect=OSError)
+def test_get_logger_config_read_only_system(mock_mkdir, mock_user_data_dir):
+    """Return empty config if the whole system is read‑only."""
+    # Run
+    config = get_sdv_logger_config()
+
+    # Assert
+    assert config == {}
+    mock_mkdir.assert_called_once()
+
+
 @patch('sdv.logging.utils.platformdirs.user_data_dir')
 @patch('sdv.logging.utils.Path.mkdir', side_effect=PermissionError)
 @patch('sdv.logging.utils.os.access', return_value=False)