risingwavelabs/risingwave · warning

anyhow!(err_msg)

Error message

anyhow!(err_msg)

What it means

In Java_com_risingwave_java_binding_Binding_sendCdcSourceErrorToChannel, a Java error message string is converted to a Rust String and wrapped with anyhow! before being sent as Err(...) over the JNI channel to the Rust consumer. The anyhow! here is the transport wrapper for the error payload — the message originates from the Java CDC connector and is delivered as an anyhow::Error to whoever receives from the channel. If the channel send itself fails, JNI_FALSE is returned and the error is logged.

Source

Thrown at src/jni_core/src/lib.rs:1109

                tracing::info!(error = %e.as_report(), "send error");
                Ok(JNI_FALSE)
            }
        }
    })
}

#[unsafe(no_mangle)]
extern "system" fn Java_com_risingwave_java_binding_Binding_sendCdcSourceErrorToChannel<'a>(
    env: EnvParam<'a>,
    channel: Pointer<'a, JniSenderType<GetEventStreamResponse>>,
    msg: JString<'a>,
) -> jboolean {
    execute_and_catch(env, move |env| {
        let ret = env.get_string(&msg);
        match ret {
            Ok(str) => {
                let err_msg: String = str.into();
                match channel.as_ref().blocking_send(Err(anyhow!(err_msg))) {
                    Ok(_) => Ok(JNI_TRUE),
                    Err(e) => {
                        tracing::info!(error = ?e.as_report(), "send error");
                        Ok(JNI_FALSE)
                    }
                }
            }
            Err(err) => {
                if msg.is_null() {
                    tracing::warn!("source error message is null");
                    Ok(JNI_TRUE)
                } else {
                    tracing::error!(error = ?err.as_report(), "source error message should be a java string");
                    Ok(JNI_FALSE)
                }
            }
        }
    })

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Check JNI_TRUE/JNI_FALSE return value: FALSE means the channel was closed — the Rust consumer must keep the receiver alive until the source is torn down
  2. Inspect Rust logs for 'send error' to see why the relay failed
  3. Fix the underlying CDC source error in the Java message; the anyhow! payload itself is the diagnostic
  4. Ensure graceful shutdown ordering: stop the Java source before dropping the Rust receiver

Example fix

// before
receiver.close(); // then Java sends error -> blocking_send fails
// after
// keep receiver alive until source is fully stopped, then drop it
let resp = rx.recv().await; // consume the Err(anyhow!(msg)) payload
Defensive patterns

Strategy: try-catch

Validate before calling

// Java, before sending
if (channelPtr == 0) return; // channel already closed on the Rust side
if (msg == null) msg = "unknown cdc source error";

Try / catch

boolean ok = Binding.sendCdcSourceErrorToChannel(channelPtr, msg);
if (!ok) {
    // channel closed: Rust receiver dropped; fall back to local logging
    log.warn("failed to relay source error to rust: " + msg);
}

Prevention

When it happens

Trigger: Java code calls sendCdcSourceErrorToChannel(channelPointer, msg) to propagate a CDC source error into Rust; the msg string is converted and injected into the channel. Returns false only when the tokio channel is closed/full on the Rust side.

Common situations: Rust side dropped the GetEventStreamResponse receiver while Java still reports a source error; blocking_send fails during shutdown; a CDC source (Kafka/Debezium) failed and the error is being relayed.

Related errors


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