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

Failed to check namespace exists.

Error message

Failed to check namespace exists.

What it means

`JniCatalog::namespace_exists` performs an existence check through the JVM catalog via JNI. Failures of the JNI call, Java-side exception, or response parsing are wrapped as an iceberg `Unexpected` error with the message 'Failed to check namespace exists.' and the underlying error as source.

Solutions

  1. Inspect the attached source error for the root Java exception.
  2. Verify catalog endpoint, credentials and network connectivity.
  3. Ensure the JNI/JVM environment for the backend is properly installed.
  4. Retry after the catalog service recovers.
Defensive patterns

Strategy: retry

Validate before calling

// Verify catalog config keys (endpoint/credentials) are present before calls
fn catalog_config_ok(props: &serde_json::Value) -> bool {
    props.get("catalog.uri").is_some() && props.get("catalog.type").is_some()
}

Try / catch

match catalog.namespace_exists(&ns).await {
    Err(e) if e.kind() == iceberg::ErrorKind::Unexpected => {
        tracing::warn!(source = ?e.source(), "namespace_exists check failed; retrying with backoff");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling namespace_exists (directly or from CREATE SINK/TABLE validation) when the JNI/Java catalog call fails.

Common situations: Catalog service temporarily unavailable; bad credentials; missing Java classes on classpath; network partition to the catalog backend.

Related errors


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

Appendix: source

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

    async fn namespace_exists(&self, namespace: &NamespaceIdent) -> iceberg::Result<bool> {
        let inner = self.inner.clone();
        let namespace = namespace.clone();
        execute_blocking_jni(move || {
            execute_with_jni_env(inner.jvm, |env| {
                let namespace_str = namespace_to_string(&namespace);
                let namespace_jstr = env.new_string(&namespace_str).unwrap();

                let exists =
                    call_method!(env, inner.java_catalog.as_obj(), {boolean namespaceExists(String)},
                    &namespace_jstr)
                    .with_context(|| format!("Failed to check namespace exists: {namespace}"))?;

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

    /// Drop a namespace from the catalog.
    async fn drop_namespace(&self, _namespace: &NamespaceIdent) -> iceberg::Result<()> {
        todo!()
    }

    /// List tables from namespace.
    async fn list_tables(&self, namespace: &NamespaceIdent) -> iceberg::Result<Vec<TableIdent>> {
        let inner = self.inner.clone();
        let namespace = namespace.clone();
        execute_blocking_jni(move || {
            execute_with_jni_env(inner.jvm, |env| {

View on GitHub (pinned to 6469eb736d)