risingwavelabs/risingwave · error · iceberg::Error (ErrorKind::Unexpected)

Failed to load iceberg table.

Error message

Failed to load iceberg table.

What it means

JniCatalog::load_table wraps any error surfaced from the JNI call stack (Java exception, JNIEnv failure, or join error) into this generic Unexpected iceberg error, attaching the original as its source. It is a wrapper error; the real cause is in with_source(e).

Source

Thrown at src/connector/src/connector_common/iceberg/jni_catalog.rs:393

                );

                let table_metadata = resp.metadata;

                let file_io = FileIOBuilder::new(Arc::new(OpenDalResolvingStorageFactory::new()))
                    .with_props(file_io_props.iter())
                    .build();

                Ok(Table::builder()
                    .file_io(file_io)
                    .identifier(table)
                    .metadata(table_metadata)
                    .runtime(runtime)
                    .build())
            })
        })
        .await
        .map_err(|e| {
            iceberg::Error::new(
                iceberg::ErrorKind::Unexpected,
                "Failed to load iceberg table.",
            )
            .with_source(e)
        })?
    }

    /// Drop a table from the catalog.
    async fn drop_table(&self, table: &TableIdent) -> iceberg::Result<()> {
        let inner = self.inner.clone();
        let table = table.to_owned();
        execute_blocking_jni(move || {
            execute_with_jni_env(inner.jvm, |env| {
                let table_name_str = table.to_string();

                let table_name_jstr = env.new_string(&table_name_str).unwrap();

                call_method!(env, inner.java_catalog.as_obj(), {boolean dropTable(String)},

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Inspect the with_source error chain to find the underlying JNI/Java exception
  2. Verify catalog properties (uri, warehouse, catalog type) are correct and complete
  3. Ensure the JVM is initialized and the Iceberg Java runtime jar is on the classpath
  4. Check the Java-side catalog connectivity (network, credentials) to the backend
  5. Look for panics in the surrounding closure in jni_catalog.rs logs
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate catalog config before calling load
assert!(!props.get("uri").unwrap_or_default().is_empty(), "catalog uri required");
// Ensure JVM is up before JNI catalog use
// jvm::ensure_initialized()?;

Type guard

fn is_jni_load_failure(err: &iceberg::Error) -> bool {
    err.kind() == iceberg::ErrorKind::Unexpected && err.message().contains("Failed to load iceberg table.")
}

Try / catch

match catalog.load_table(&ident).await {
    Err(e) if e.message().contains("Failed to load iceberg table.") => {
        tracing::error!(source = ?e.source(), "jni load_table failed");
        // inspect Java-side cause, retry transient errors
    }
    other => other,
}

Prevention

When it happens

Trigger: The Java/JNI catalog call invoked inside tokio::task::block_in_place (from purge_table) returns Err — e.g. Java exception during catalog.loadTable, missing JVM class, bad catalog properties, or a tokio JoinError when the spawned closure panics.

Common situations: Missing or wrong catalog properties (warehouse URI, catalog type) passed to the Java catalog; JVM not initialized or classpath missing the Iceberg runtime; network/auth failure reaching Hive/Gluc/Nessie from the Java side; closure panic in the async block.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/13e5a62c2a62d3fe. Report an issue: GitHub.