diff --git a/swh/loader/cvs/loader.py b/swh/loader/cvs/loader.py
index f2db1b972a1b58b9122f7c89818fe23c999daa4a..1990e174c653c417623556202bc183663bf0f040 100644
--- a/swh/loader/cvs/loader.py
+++ b/swh/loader/cvs/loader.py
@@ -401,9 +401,14 @@ class CvsLoader(BaseLoader):
     def fetch_cvs_repo_with_rsync(self, host: str, path: str) -> None:
         # URL *must* end with a trailing slash in order to get CVSROOT listed
         url = "rsync://%s%s/" % (host, os.path.dirname(path))
-        rsync = self.execute_rsync(
-            ["rsync", url], capture_output=True, encoding="utf-8"
-        )
+        try:
+            rsync = self.execute_rsync(
+                ["rsync", url], capture_output=True, encoding="utf-8"
+            )
+        except subprocess.CalledProcessError as cpe:
+            if cpe.returncode == 23 and "No such file or directory" in cpe.stderr:
+                raise NotFound("CVS repository not found at {url}")
+            raise
         have_cvsroot = False
         have_module = False
         for line in rsync.stdout.split("\n"):
diff --git a/swh/loader/cvs/tests/test_loader.py b/swh/loader/cvs/tests/test_loader.py
index 6c16c8d18702fdded3701aaa83cbecf3c6feb91b..52c06a308109275b04aac353b6e14b47bfe35fc4 100644
--- a/swh/loader/cvs/tests/test_loader.py
+++ b/swh/loader/cvs/tests/test_loader.py
@@ -1374,3 +1374,20 @@ def test_loader_cvs_with_missing_cvs_config_file(swh_storage, datadir, tmp_path)
     )
 
     assert loader.load() == {"status": "eventful"}
+
+
+def test_loader_cvs_rsync_not_found(swh_storage, mocker):
+    origin_url = "rsync://example.org/cvsroot/module"
+    loader = CvsLoader(swh_storage, origin_url)
+    mocker.patch.object(
+        loader, "execute_rsync"
+    ).side_effect = subprocess.CalledProcessError(
+        returncode=23,
+        cmd=["rsync", origin_url],
+        stderr='rsync: change_dir "/module" (in cvsroot) failed: No such file or directory (2)',
+    )
+    assert loader.load() == {"status": "uneventful"}
+    visit_status = (
+        swh_storage.origin_visit_get_with_statuses(origin_url).results[-1].statuses[-1]
+    )
+    assert visit_status.status == "not_found"