risingwavelabs/risingwave · error
Input object is not a java string and can't be converted!
Error message
Input object is not a java string and can't be converted!
What it means
jobj_to_str converts a returned Java object to a Rust String but first verifies the object is an instance of java/lang/String. If it is not, it bails with this error instead of attempting an unsafe cast. It guards JNI calls whose Java methods are expected to return strings (namespace/table names, exception messages).
Solutions
- Ensure the connector/iceberg jars in CONNECTOR_LIBS_PATH match the versions RisingWave expects (risingwave-source-cdc first on classpath).
- Inspect the Java method being called and confirm its return type is String.
- Check whether the returned object is null/None from the Java side and handle it before conversion.
- Update or reinstall the connector package to fix signature drift.
Example fix
// before (java side)
public Object listTables() { return tablesList; } // returns List, not String
// after (java side)
public String listTables() { return serialize(tablesList); } Defensive patterns
Strategy: try-catch
Validate before calling
// verify expected jar version is on the classpath ls "$CONNECTOR_LIBS_PATH" | grep -q 'risingwave-connector' && echo ok || echo 'connector jars missing or outdated'
Try / catch
match catalog.list_tables() {
Err(e) if e.to_string().contains("not a java string") => {
// suspect jar version mismatch or null return; refresh jars and retry
}
other => other?,
} Prevention
- Keep connector jars pinned to the versions RisingWave documents; update them together.
- Never substitute hand-patched jars without checking return-type signatures.
- Add a startup assertion that the Java methods used return String where expected.
- Handle null returns on the Java side so JNI never receives a non-String.
When it happens
Trigger: A Java method invoked via list_namespaces, list_tables, create_table, load_table, update_table, or execute_with_jni_env returns a non-String object where a String was expected, e.g. a patched/incorrect Debezium-Iceberg jar returning a different type.
Common situations: Mismatched jar versions where the Java method signature changed and now returns an array or custom type, a null object being returned by the Java side, using an outdated or hand-patched connector jar.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Caught Java Exception
- fail to new JVM
- Failed to check namespace exists.
- Failed to create iceberg table.
- Failed to create namespace.
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/9aa457a5e76e0eb3.
Report an issue: GitHub.
Appendix: source
Thrown at src/jni_core/src/jvm_runtime.rs:270
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);
let java_str = env.get_string(&jstr)?;
Ok(java_str.to_str()?.to_owned())
}
/// Dumps the JVM stack traces.
///
/// # Returns
///
/// - `Ok(None)` if JVM is not initialized.
/// - `Ok(Some(String))` if JVM is initialized and stack traces are dumped.
/// - `Err` if failed to dump stack traces.
pub fn dump_jvm_stack_traces() -> anyhow::Result<Option<String>> {
match Jvm::get() {
None => Ok(None),
Some(jvm) => execute_with_jni_env(jvm, |env| {
let result = call_static_method!(View on GitHub (pinned to 6469eb736d)