From 89bdd08575c2d121cd0cc71df946e8c8df266cdf Mon Sep 17 00:00:00 2001 From: NoiceHax Date: Sat, 15 Aug 2026 15:11:13 +0530 Subject: [PATCH 1/2] fix: point at open_mfdataset when open_dataset gets a list of paths Passing a list or tuple of paths to open_dataset failed with the generic "did not find a match in any of xarray's currently installed IO backends" message, which does not hint at the actual mistake. The check sits at the end of guess_engine, right after the existing FileNotFoundError check, so backends that do accept a sequence still get their chance to claim the input first. Co-authored-by: Claude --- doc/whats-new.rst | 4 ++++ pyproject.toml | 1 + xarray/backends/plugins.py | 6 ++++++ xarray/tests/test_plugins.py | 10 ++++++++++ 4 files changed, 21 insertions(+) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 0e74ca1e2fc..84b32cdb279 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -49,6 +49,10 @@ Deprecations Bug Fixes ~~~~~~~~~ +- :py:func:`~xarray.open_dataset` now raises an error pointing at + :py:func:`~xarray.open_mfdataset` when it is given a list or tuple of paths, + instead of reporting that no IO backend matched the input (:issue:`6510`). + By `NoiceHax `_. - Fix async zarr tests using ``wraps`` with ``autospec=True`` on async methods, which caused ``AsyncMock`` objects to leak through instead of real array data (:pull:`11232`). diff --git a/pyproject.toml b/pyproject.toml index 828bee18fa5..6fad5adacff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -424,6 +424,7 @@ Claus = "Claus" Celles = "Celles" slowy = "slowy" Commun = "Commun" +Noice = "Noice" # Tests Ome = "Ome" diff --git a/xarray/backends/plugins.py b/xarray/backends/plugins.py index db79dbae7ff..619ba2af32f 100644 --- a/xarray/backends/plugins.py +++ b/xarray/backends/plugins.py @@ -214,6 +214,12 @@ def guess_engine( if not is_remote_uri(store_spec_str) and not os.path.exists(store_spec_str): raise FileNotFoundError(f"No such file: '{store_spec_str}'") + if isinstance(store_spec, list | tuple): + raise ValueError( + f"open_dataset opens a single file, but got a {type(store_spec).__name__}. " + "Use open_mfdataset to open multiple files as a single dataset." + ) + raise ValueError(error_msg) diff --git a/xarray/tests/test_plugins.py b/xarray/tests/test_plugins.py index b41d18ae418..efee26b0b58 100644 --- a/xarray/tests/test_plugins.py +++ b/xarray/tests/test_plugins.py @@ -250,6 +250,16 @@ def test_guess_engine_file_not_found() -> None: plugins.guess_engine("https://example.com/missing.h5") +@mock.patch( + "xarray.backends.plugins.list_engines", + mock.MagicMock(return_value={"dummy": DummyBackendEntrypointArgs()}), +) +@pytest.mark.parametrize("paths", [["a.nc", "b.nc"], ("a.nc", "b.nc")]) +def test_guess_engine_sequence_of_paths(paths) -> None: + with pytest.raises(ValueError, match=r"Use open_mfdataset"): + plugins.guess_engine(paths) + + @pytest.mark.parametrize("engine", common.BACKEND_ENTRYPOINTS.keys()) def test_get_backend_fastpath_skips_list_engines(engine: str) -> None: """Test that built-in engines skip list_engines (fastpath).""" From d7ca89c920dcea2cdb042223db9ecde6874151ca Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 15 Aug 2026 11:10:01 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- doc/whats-new.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 84b32cdb279..87142bbf987 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -52,7 +52,7 @@ Bug Fixes - :py:func:`~xarray.open_dataset` now raises an error pointing at :py:func:`~xarray.open_mfdataset` when it is given a list or tuple of paths, instead of reporting that no IO backend matched the input (:issue:`6510`). - By `NoiceHax `_. + By `NoiceHex `_. - Fix async zarr tests using ``wraps`` with ``autospec=True`` on async methods, which caused ``AsyncMock`` objects to leak through instead of real array data (:pull:`11232`).