From 31820177d35fb6c47fc37b2be9002bb675cd1937 Mon Sep 17 00:00:00 2001 From: Vincent Gao Date: Thu, 18 Jun 2026 00:09:35 +0200 Subject: [PATCH] fix: handle OSError in _get_mtime for non-file paths (fixes #11386) _get_mtime calls os.path.getmtime on any non-remote path, but some paths that look like local filesystem paths are actually GDAL virtual filesystems (/vsicurl/..., /vsis3/...) or other URI schemes that don't support stat(). Wrap the call in suppress(OSError) to avoid crashing on these paths. --- xarray/backends/api.py | 4 +++- xarray/tests/test_backends.py | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/xarray/backends/api.py b/xarray/backends/api.py index fd992f3e5d8..4ca7207b3a8 100644 --- a/xarray/backends/api.py +++ b/xarray/backends/api.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib import os from collections.abc import ( Callable, @@ -102,7 +103,8 @@ def _get_mtime(filename_or_obj): path = None if path and not is_remote_uri(path): - mtime = os.path.getmtime(os.path.expanduser(filename_or_obj)) + with contextlib.suppress(OSError): + mtime = os.path.getmtime(os.path.expanduser(filename_or_obj)) return mtime diff --git a/xarray/tests/test_backends.py b/xarray/tests/test_backends.py index 1746235cedc..71a465aa8cf 100644 --- a/xarray/tests/test_backends.py +++ b/xarray/tests/test_backends.py @@ -8140,3 +8140,14 @@ def test_h5netcdf_storage_options() -> None: storage_options={"skip_instance_cache": False}, ) as ds: assert_identical(xr.concat([ds1, ds2], dim="time", data_vars="all"), ds) + + +def test_get_mtime_non_file_paths() -> None: + """_get_mtime should not raise on non-file paths (gh#11386).""" + from xarray.backends.api import _get_mtime + + # Non-existent local path should return None, not crash + assert _get_mtime("/nonexistent/path.nc") is None + + # GDAL virtual filesystem paths are not real files + assert _get_mtime("/vsicurl/https://example.com/file.nc") is None