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
- Read the string message to find which executor code path produced it.
- Replace String-based error returns in the source with typed errors for better diagnostics (maintainer-side fix).
- Trace with the backtrace attached by the Uncategorized variant to locate the raise site.
- 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
- Replace String-typed error returns in executor helpers with typed errors.
- Use thiserror/thiserror_ext variants instead of raw strings for new code.
- Attach context with anyhow::Context when constructing ad-hoc messages.
- Grep for From<String> usages when auditing error paths.
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
- builder should have yielded a chunk
- Channel closed
- compaction resolver sink
- compaction resolver sink
- compaction resolver sink
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)