apache/iceberg · error · UnsupportedOperationException

Failed to load Configuration after loading Configurable

Error message

Failed to load Configuration after loading Configurable

What it means

CatalogUtil.configureHadoopConf loads the Hadoop Configuration class reflectively after successfully loading a Configurable (a Catalog or FileIO). If Configuration itself cannot be loaded via the same classloader, this UnsupportedOperationException is thrown. The code comments note this 'shouldn't happen' because a Configurable cannot be loaded without first loading Configuration, so it indicates a corrupted or inconsistent classloader state.

Solutions

  1. Verify Hadoop's configuration classes are on the classpath of the same classloader that loads the catalog/FileIO implementation.
  2. Inspect any custom classloader passed via ClassLoader and ensure it delegates to the parent for org.apache.hadoop.* classes.
  3. Check for shading/relocation of org.apache.hadoop.conf.Configuration in a fat jar and un-relocate it or add the real hadoop-common dependency.
  4. Align Hadoop versions so the Configuration class is loadable by CatalogUtil's configured loader (catalog.loader.impl / catalog.classloader properties).

Example fix

// before (broken: custom classloader filters hadoop classes)
CatalogUtil.loadCatalog("org.apache.iceberg.hive.HiveCatalog", "hive", null, myIsolatingClassLoader);

// after (fix classloader delegation or use default loader)
CatalogUtil.loadCatalog("org.apache.iceberg.hive.HiveCatalog", "hive", null,
    Thread.currentThread().getContextClassLoader());
Defensive patterns

Strategy: try-catch

Validate before calling

ClassLoader cl = pluginClassLoader;
Class<?> conf = Class.forName("org.apache.hadoop.conf.Configuration", true, cl);
if (conf == null) { throw new IllegalStateException("Hadoop Configuration not loadable by plugin classloader"); }

Type guard

boolean hasHadoopConf(ClassLoader cl) {
  try { Class.forName("org.apache.hadoop.conf.Configuration", false, cl); return true; }
  catch (ClassNotFoundException e) { return false; }
}

Try / catch

try {
  CatalogUtil.loadCatalog(impl, name, properties, conf);
} catch (UnsupportedOperationException e) {
  if (e.getCause() instanceof ClassNotFoundException) {
    // fall back to default classloader or fail fast with a clear setup error
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling CatalogUtil.loadCatalog(...) or loadFileIO(...) with a custom classloader where the Configurable class loads but org.apache.hadoop.conf.Configuration does not resolve via DynClasses; or a classloader whose parent delegation is broken/filtered (shaded environments, exotic plugin classloaders).

Common situations: Hadoop jars are shaded/relocated or absent from the runtime classpath but a stub Configurable class is present; custom plugin classloaders that hide org.apache.hadoop packages; mismatched classloader hierarchies in Flink/Spark/Hive metastore plugin setups.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/31359915ca8833cd. Report an issue: GitHub.

Appendix: source

Thrown at core/src/main/java/org/apache/iceberg/CatalogUtil.java:478

      return;
    }

    if (!configurableInterface.isInstance(maybeConfigurable)) {
      // not Configurable because the object does not implement the Configurable interface
      return;
    }

    Class<?> configurationClass;
    try {
      configurationClass =
          DynClasses.builder()
              .loader(maybeConfigurableLoader)
              .impl("org.apache.hadoop.conf.Configuration")
              .buildChecked();
    } catch (ClassNotFoundException e) {
      // this shouldn't happen because Configurable cannot be loaded without first loading
      // Configuration
      throw new UnsupportedOperationException(
          "Failed to load Configuration after loading Configurable", e);
    }

    ValidationException.check(
        configurationClass.isInstance(conf),
        "%s is not an instance of Configuration from the classloader for %s",
        conf,
        maybeConfigurable);

    DynMethods.BoundMethod setConf;
    try {
      setConf =
          DynMethods.builder("setConf")
              .impl(configurableInterface, configurationClass)
              .buildChecked()
              .bind(maybeConfigurable);
    } catch (NoSuchMethodException e) {
      // this shouldn't happen because Configurable was loaded and defines setConf

View on GitHub (pinned to 86d9c8fc54)