risingwavelabs/risingwave · error · anyhow
Caught Java Exception: {}
Error message
Caught Java Exception: {} What it means
After invoking a Java method through JNI (via the execute_with_jni_env wrapper used by all Iceberg REST catalog operations), the code checks ExceptionCheck. If a Java exception is pending, its message is extracted via getMessage() and returned as a Rust error prefixed with `Caught Java Exception:`. This surfaces underlying Java-side failures (network to catalog, auth, schema issues) into Rust error handling.
Source
Thrown at src/jni_core/src/jvm_runtime.rs:254
&system_class_loader
)?;
let ret = f(&mut env);
match env.exception_check() {
Ok(true) => {
let exception = env.exception_occurred().inspect_err(|e| {
tracing::warn!(error = %e.as_report(), "Failed to get jvm exception");
})?;
env.exception_describe().inspect_err(|e| {
tracing::warn!(error = %e.as_report(), "Failed to describe jvm exception");
})?;
env.exception_clear().inspect_err(|e| {
tracing::warn!(error = %e.as_report(), "Exception occurred but failed to clear");
})?;
let message = call_method!(env, exception, {String getMessage()})?;
let message = jobj_to_str(&mut env, message)?;
return Err(anyhow::anyhow!("Caught Java Exception: {}", message));
}
Ok(false) => {
// No exception, do nothing
}
Err(e) => {
tracing::warn!(error = %e.as_report(), "Failed to check exception");
}
}
ret
}
/// A helper method to convert an java object to rust string.
pub fn jobj_to_str(env: &mut JNIEnv<'_>, obj: JObject<'_>) -> anyhow::Result<String> {
if !env.is_instance_of(&obj, "java/lang/String")? {
bail!("Input object is not a java string and can't be converted!")
}
let jstr = JString::from(obj);View on GitHub (pinned to 6469eb736d)
Solutions
- Read the Java message after `Caught Java Exception:` — it names the actual Java-side cause.
- Verify the Iceberg catalog URI, credentials, and warehouse config are correct.
- Ensure all required jars are present in CONNECTOR_LIBS_PATH (classpath complete).
- Fix the specific catalog error (auth, existing object, network) indicated by the message.
- Re-run with Java-side logging enabled for a full stack trace.
Example fix
// before LOAD TABLE iceberg_t FROM iceberg WITH (catalog.uri='http://wrong-host:9000/catalog') // after LOAD TABLE iceberg_t FROM iceberg WITH (catalog.uri='http://catalog-host:9000/catalog', catalog.credential='...')
Defensive patterns
Strategy: try-catch
Validate before calling
// preflight: catalog reachable
const res = await fetch(catalogUri); if (!res.ok) throw new Error(`iceberg catalog ${catalogUri} returned ${res.status}`); Try / catch
match catalog.list_namespaces() {
Err(e) if e.to_string().starts_with("Caught Java Exception:") => {
let java_msg = e.to_string();
// inspect java_msg for cause: auth, not-found, already-exists, network
}
other => other?,
} Prevention
- Verify Iceberg catalog URI, credentials, and warehouse settings before creating sources.
- Keep CONNECTOR_LIBS_PATH jars at supported versions, with risingwave-source-cdc first.
- Preflight connectivity to the catalog host/port.
- Enable Java-side stack-trace logging to map messages back to causes.
When it happens
Trigger: Any of list_namespaces, create_namespace, namespace_exists, list_tables, create_table, load_table raising a Java exception on the JNI side — e.g. Iceberg REST catalog returning HTTP 4xx/5xx, missing classpath entries causing ClassNotFoundException, or invalid arguments from Rust.
Common situations: Iceberg REST catalog unreachable or misconfigured (wrong URI/credentials), missing Debezium/iceberg jars on the classpath, OAuth token invalid on the catalog side, table/namespace already exists.
Related errors
- Failed to list iceberg namespaces.
- Failed to create namespace.
- Failed to check namespace exists.
- Failed to list iceberg tables.
- Failed to create iceberg table.
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/5cf7524c2eee4484.
Report an issue: GitHub.