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

Failed to drop iceberg table.

Error message

Failed to drop iceberg table.

What it means

JniCatalog::drop_table wraps any failure from the JNI drop-table operation (Java exception or join error on the block_in_place task) into this Unexpected iceberg error with the original error attached as source. The table was not confirmed dropped.

Source

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

    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)},
                &table_name_jstr)
                .with_context(|| format!("Failed to drop iceberg table: {table_name_str}"))?;

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

    async fn purge_table(&self, table: &TableIdent) -> iceberg::Result<()> {
        let table_info = self.load_table(table).await?;
        self.drop_table(table).await?;
        iceberg::drop_table_data(&table_info).await
    }

    async fn register_table(
        &self,
        _table_ident: &TableIdent,
        _metadata_location: String,
    ) -> iceberg::Result<Table> {

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Check the attached source error for the underlying Java exception
  2. Confirm the table exists and the catalog credentials have DROP permission
  3. Verify JVM setup and that the backend catalog is reachable
  4. Retry the drop if the failure was transient (network/timeout)
  5. Use catalog-level checks (table_exists) before dropping to rule out not-found semantics
Defensive patterns

Strategy: try-catch

Validate before calling

if !catalog.table_exists(&ident).await? {
    return Ok(()); // nothing to drop
}

Type guard

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

Try / catch

if let Err(e) = catalog.drop_table(&ident).await {
    if e.message().contains("Failed to drop iceberg table.") {
        // check source for Java exception; retry if transient
        tracing::error!(source = ?e.source(), "drop failed");
    }
}

Prevention

When it happens

Trigger: The JNI call to drop the table in drop_table (called via purge_table) returns Err: Java-side exception (table does not exist per backend policy, auth failure, connection issue), JNIEnv error, or the spawned task panicked (JoinError).

Common situations: Dropping a table that the Java catalog refuses to drop (e.g. missing or access-denied); JVM/classpath problems; transient backend unavailability when purging Iceberg tables from RisingWave.

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