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

JingsongLi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git


The following commit(s) were added to refs/heads/master by this push:
     new 083170ad71 [common] Keep unchecked loader failures in FileIO.get 
(#10752)
083170ad71 is described below

commit 083170ad71fe01659e457e0d5cc02c007d7a1b76
Author: Etienne Chauchot <[email protected]>
AuthorDate: Mon Oct 26 07:23:01 2026 +0100

    [common] Keep unchecked loader failures in FileIO.get (#10752)
---
 .../src/main/java/org/apache/paimon/fs/FileIO.java | 29 +++++++++--
 .../test/java/org/apache/paimon/fs/FileIOTest.java | 58 ++++++++++++++++++++++
 2 files changed, 82 insertions(+), 5 deletions(-)

diff --git a/paimon-common/src/main/java/org/apache/paimon/fs/FileIO.java 
b/paimon-common/src/main/java/org/apache/paimon/fs/FileIO.java
index 16efe5f6a6..2863092639 100644
--- a/paimon-common/src/main/java/org/apache/paimon/fs/FileIO.java
+++ b/paimon-common/src/main/java/org/apache/paimon/fs/FileIO.java
@@ -656,12 +656,20 @@ public interface FileIO extends Serializable, Closeable {
                                 + fallbackIO.getClass().getSimpleName()
                                 + " also cannot access this path.";
             }
+            String firstErrorMsg = "";
+            if (!ioExceptionList.isEmpty()) {
+                Throwable rootCause = ioExceptionList.get(0);
+                while (rootCause.getCause() != null && rootCause.getCause() != 
rootCause) {
+                    rootCause = rootCause.getCause();
+                }
+                firstErrorMsg = " First error: " + rootCause;
+            }
             UnsupportedSchemeException ex =
                     new UnsupportedSchemeException(
                             String.format(
                                     "Could not find a file io implementation 
for scheme '%s' in the classpath."
-                                            + "%s %s Hadoop FileSystem also 
cannot access this path '%s'.",
-                                    uri.getScheme(), preferMsg, fallbackMsg, 
path));
+                                            + "%s %s Hadoop FileSystem also 
cannot access this path '%s'.%s",
+                                    uri.getScheme(), preferMsg, fallbackMsg, 
path, firstErrorMsg));
             for (IOException ioException : ioExceptionList) {
                 ex.addSuppressed(ioException);
             }
@@ -704,9 +712,20 @@ public interface FileIO extends Serializable, Closeable {
         }
 
         // check access
-        FileIO io = fileIO.load(path);
-        io.configure(config);
-        io.exists(path);
+        try {
+            FileIO io = fileIO.load(path);
+            io.configure(config);
+            io.exists(path);
+        } catch (RuntimeException | LinkageError e) {
+            // Keep unchecked failures (e.g. Hadoop's RuntimeException 
wrapping a
+            // ClassNotFoundException when the file system class of the scheme 
is missing) so that
+            // the caller reports them together with the failures of the other 
loaders, instead
+            // of letting them hide those failures.
+            throw new IOException(
+                    String.format(
+                            "%s cannot access path '%s'.", 
fileIO.getClass().getSimpleName(), path),
+                    e);
+        }
         return fileIO;
     }
 }
diff --git a/paimon-common/src/test/java/org/apache/paimon/fs/FileIOTest.java 
b/paimon-common/src/test/java/org/apache/paimon/fs/FileIOTest.java
index 6642f7b62a..7482177355 100644
--- a/paimon-common/src/test/java/org/apache/paimon/fs/FileIOTest.java
+++ b/paimon-common/src/test/java/org/apache/paimon/fs/FileIOTest.java
@@ -178,6 +178,34 @@ public class FileIOTest {
         
assertThat(fileIO).isInstanceOf(RequireOptionsFileIOLoader.MyFileIO.class);
     }
 
+    @Test
+    public void testGetKeepsUncheckedFailuresOfLoaders() {
+        RuntimeException preferFailure =
+                new RuntimeException(
+                        new ClassNotFoundException(
+                                "Class org.apache.hadoop.fs.s3a.S3AFileSystem 
not found"));
+        IOException fallbackFailure = new IOException("The specified bucket 
does not exist");
+        CatalogContext context =
+                CatalogContext.create(
+                        new Options(),
+                        new FailingFileIOLoader(preferFailure),
+                        new FailingFileIOLoader(fallbackFailure));
+
+        assertThatThrownBy(() -> FileIO.get(new 
Path("failing-scheme://bucket/path"), context))
+                .isInstanceOf(UnsupportedSchemeException.class)
+                .hasMessageContaining(
+                        "First error: java.lang.ClassNotFoundException: "
+                                + "Class 
org.apache.hadoop.fs.s3a.S3AFileSystem not found")
+                .satisfies(
+                        e -> {
+                            assertThat(e.getSuppressed()[0])
+                                    .isInstanceOf(IOException.class)
+                                    .hasMessageContaining("FailingFileIOLoader 
cannot access path")
+                                    .hasCause(preferFailure);
+                            
assertThat(e.getSuppressed()).contains(fallbackFailure);
+                        });
+    }
+
     @Test
     public void testCopy() throws Exception {
         Path srcFile = new Path(tempDir.resolve("src.txt").toUri());
@@ -445,4 +473,34 @@ public class FileIOTest {
             return new File(localPath);
         }
     }
+
+    /** A {@link FileIOLoader} whose {@link FileIO} fails the access check 
with a given failure. */
+    private static class FailingFileIOLoader implements FileIOLoader {
+
+        private static final long serialVersionUID = 1L;
+
+        private final Exception failure;
+
+        private FailingFileIOLoader(Exception failure) {
+            this.failure = failure;
+        }
+
+        @Override
+        public String getScheme() {
+            return "failing-scheme";
+        }
+
+        @Override
+        public FileIO load(Path path) {
+            return new LocalFileIO() {
+                @Override
+                public boolean exists(Path path) throws IOException {
+                    if (failure instanceof IOException) {
+                        throw (IOException) failure;
+                    }
+                    throw (RuntimeException) failure;
+                }
+            };
+        }
+    }
 }

Reply via email to