risingwavelabs/risingwave · error · StreamExecutorError

{}

Error message

{}

What it means

This From<String> impl (src/stream/src/executor/error.rs:151) turns an arbitrary String into a StreamExecutorError by wrapping it in ErrorKind::Uncategorized(anyhow::anyhow!(s)). The rendered message is just the string itself ('{}'), so the string becomes the entire error text. It is the generic entry point for ad-hoc error messages in executor code.

Solutions

  1. Read the string message to find which executor code path produced it.
  2. Replace String-based error returns in the source with typed errors for better diagnostics (maintainer-side fix).
  3. Trace with the backtrace attached by the Uncategorized variant to locate the raise site.
  4. Handle it as an unexpected internal error; restart/failover will typically recover the actor.

Example fix

// before
fn helper() -> Result<(), String> { ... Err("bad state".to_string())? }
// after
fn helper() -> StreamExecutorResult<()> { ... bail!("bad state") }
Defensive patterns

Strategy: type-guard

Type guard

fn is_string_error(e: &StreamExecutorError) -> bool {
    // From<String> lands in Uncategorized; treat non-variant messages as ad-hoc
    e.variant_name() == "Uncategorized"
}

Try / catch

if let Err(e) = result {
    if e.variant_name() == "Uncategorized" {
        // the message IS the string passed to From<String>; log and fail over
        tracing::error!(msg = %e, "ad-hoc executor error");
    }
    return Err(e);
}

Prevention

When it happens

Trigger: Raised wherever a `?` on a `Result<_, String>` or an explicit `.into()`/`StreamExecutorError::from(String)` occurs in stream executor code, e.g. helper functions that report failures as plain strings.

Common situations: Legacy or quick internal error paths that return String messages; errors from utility code not using typed errors; dynamic messages assembled at runtime.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at src/stream/src/executor/error.rs:153

/// Connector error.
impl From<ConnectorError> for StreamExecutorError {
    fn from(s: ConnectorError) -> Self {
        Self::connector_error(s)
    }
}

impl From<PbFieldNotFound> for StreamExecutorError {
    fn from(err: PbFieldNotFound) -> Self {
        Self::from(anyhow::anyhow!(
            "Failed to decode prost: field not found `{}`",
            err.0
        ))
    }
}

impl From<String> for StreamExecutorError {
    fn from(s: String) -> Self {
        ErrorKind::Uncategorized(anyhow::anyhow!(s)).into()
    }
}

impl From<(SinkError, SinkId)> for StreamExecutorError {
    fn from((err, sink_id): (SinkError, SinkId)) -> Self {
        ErrorKind::SinkError(err, sink_id).into()
    }
}

impl StreamExecutorError {
    pub fn variant_name(&self) -> &str {
        self.0.inner().as_ref()
    }
}

static_assertions::const_assert_eq!(std::mem::size_of::<StreamExecutorError>(), 8);

#[cfg(test)]

View on GitHub (pinned to 6469eb736d)