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

Failed to check iceberg table exists.

Error message

Failed to check iceberg table exists.

What it means

JniCatalog::table_exists wraps failures from the JNI existence-check call into this Unexpected iceberg error with the underlying error attached. This is not a 'table does not exist' result — that returns Ok(false); this error means the check itself failed.

Source

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

        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();

                let exists =
                    call_method!(env, inner.java_catalog.as_obj(), {boolean tableExists(String)},
                    &table_name_jstr)
                    .with_context(|| {
                        format!("Failed to check iceberg table exists: {table_name_str}")
                    })?;

                Ok(exists)
            })
        })
        .await
        .map_err(|e| {
            iceberg::Error::new(
                iceberg::ErrorKind::Unexpected,
                "Failed to check iceberg table exists.",
            )
            .with_source(e)
        })
    }

    /// Rename a table in the catalog.
    async fn rename_table(&self, _src: &TableIdent, _dest: &TableIdent) -> iceberg::Result<()> {
        todo!()
    }

    /// Update a table to the catalog.
    async fn update_table(&self, mut commit: TableCommit) -> iceberg::Result<Table> {
        let inner = self.inner.clone();
        let file_io_props = self.file_io_props.clone();
        let runtime = Runtime::try_current()?;
        execute_blocking_jni(move || {

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Read the with_source error chain for the actual Java exception
  2. Validate the TableIdent (namespace + table name) matches what exists in the backend
  3. Check JVM initialization and classpath
  4. Retry on transient backend connectivity failures
Defensive patterns

Strategy: retry

Validate before calling

// Validate identifier before existence probe
debug_assert!(!ident.name().is_empty(), "table name required");

Type guard

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

Try / catch

let exists = loop {
    match catalog.table_exists(&ident).await {
        Ok(v) => break v,
        Err(e) if is_transient(&e) => continue, // backoff
        Err(e) => return Err(e),
    }
};

Prevention

When it happens

Trigger: The JNI/Java catalog tableExists call errors out inside the block_in_place task: Java exception (auth, connectivity, invalid identifier), JNIEnv failure, or a JoinError from a panicked closure.

Common situations: Backend catalog temporarily unreachable during existence probes; malformed TableIdent rejected by the Java catalog; JVM/classpath misconfiguration when RisingWave validates an Iceberg table reference.

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/282df942b124d8f4. Report an issue: GitHub.