risingwavelabs/risingwave · critical · anyhow

fail to new JVM

Error message

fail to new JVM

What it means

JavaVM::new failed to create the Java virtual machine after the JNI args (classpath, options, etc.) were built. The detailed JNI error is logged, and a generic `fail to new JVM` error is returned. Common causes are a missing/incompatible libjvm, wrong JAVA_HOME, bad JVM options, or insufficient memory.

Solutions

  1. Check the error log line `fail to new JVM` for the underlying JNI error code.
  2. Verify JAVA_HOME points to a full JDK (e.g. Java 11/17 as required) with lib/.../libjvm.so present.
  3. Set LD_LIBRARY_PATH to include $JAVA_HOME/lib/server so libjvm.so loads.
  4. Review CONNECTOR_LIBS_PATH/jvm options for invalid -X flags or garbage values.
  5. Confirm enough memory exists (JVM heap options not exceeding container limits).

Example fix

// before
# no JAVA_HOME, only a JRE installed
// after
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk && export LD_LIBRARY_PATH=$JAVA_HOME/lib/server:$LD_LIBRARY_PATH
Defensive patterns

Strategy: try-catch

Validate before calling

test -n "$JAVA_HOME" && test -f "$JAVA_HOME/lib/server/libjvm.so" && echo 'JVM OK' || echo 'JAVA_HOME missing or libjvm.so not found'

Try / catch

match jvm_runtime::global_jvm() {
    Err(e) if e.to_string().contains("fail to new JVM") => {
        // check JAVA_HOME, LD_LIBRARY_PATH, JDK version, then surface a clear ops message
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling build_jvm_with_native_registration when libjvm.so cannot be found/loaded, an invalid JVM option string is passed via JNI args, or the JDK version is incompatible with the expected one (e.g. Java 11 vs 17).

Common situations: JAVA_HOME unset or pointing at a JRE instead of a JDK, CONNECTOR_LIBS_PATH containing an incompatible JDK, missing libjvm.so on the loader path (LD_LIBRARY_PATH), containers without a JVM installed.

Related errors


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

Appendix: source

Thrown at src/jni_core/src/jvm_runtime.rs:123

    // Exit the embedded JVM on uncaught `OutOfMemoryError` so that the host
    // compute node process terminates and the cluster recovers via the standard
    // recovery loop, matching native OOM behavior. Set `JVM_EXIT_ON_OOM=false`
    // (or `0`) to opt out.
    let exit_on_oom = std::env::var("JVM_EXIT_ON_OOM")
        .map(|v| !matches!(v.to_ascii_lowercase().as_str(), "false" | "0" | ""))
        .unwrap_or(true);
    if exit_on_oom {
        args_builder = args_builder.option("-XX:+ExitOnOutOfMemoryError");
    }

    tracing::info!("JVM args: {:?}", args_builder);
    let jvm_args = args_builder.build().context("invalid jvm args")?;

    // Create a new VM
    let jvm = match JavaVM::new(jvm_args) {
        Err(err) => {
            tracing::error!(error = ?err.as_report(), "fail to new JVM");
            bail!("fail to new JVM");
        }
        Ok(jvm) => jvm,
    };

    tracing::info!("initialize JVM successfully");

    let result: std::result::Result<(), jni::errors::Error> = try {
        let mut env = jvm_env(&jvm)?;
        register_java_binding_native_methods(&mut env)?;
    };

    result.context("failed to register native method")?;

    Ok(jvm)
}

pub fn jvm_env(jvm: &JavaVM) -> Result<AttachGuard<'_>, jni::errors::Error> {
    jvm.attach_current_thread()

View on GitHub (pinned to 6469eb736d)