risingwavelabs/risingwave · error · SinkError::SqlServer

SinkError::SqlServer(anyhow!(err))

Error message

SinkError::SqlServer(anyhow!(err))

What it means

This is RisingWave's SinkError wrapping a tiberius (SQL Server client) error. Any error surfaced by the tiberius driver during interaction with a SQL Server sink target is converted via the From impl into the SqlServer variant, losing the typed error but preserving the message via anyhow.

Source

Thrown at src/connector/src/sink/mod.rs:1291

        SinkError::File(error.to_report_string())
    }
}

impl From<RpcError> for SinkError {
    fn from(value: RpcError) -> Self {
        SinkError::Remote(anyhow!(value))
    }
}

impl From<RedisError> for SinkError {
    fn from(value: RedisError) -> Self {
        SinkError::Redis(value.to_report_string())
    }
}

impl From<tiberius::error::Error> for SinkError {
    fn from(err: tiberius::error::Error) -> Self {
        SinkError::SqlServer(anyhow!(err))
    }
}

impl From<::elasticsearch::Error> for SinkError {
    fn from(err: ::elasticsearch::Error) -> Self {
        SinkError::ElasticSearchOpenSearch(anyhow!(err))
    }
}

impl From<::opensearch::Error> for SinkError {
    fn from(err: ::opensearch::Error) -> Self {
        SinkError::ElasticSearchOpenSearch(anyhow!(err))
    }
}

impl From<tokio_postgres::Error> for SinkError {
    fn from(err: tokio_postgres::Error) -> Self {
        SinkError::Postgres(anyhow!(err))

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Verify the SQL Server endpoint is reachable (host, port 1433, firewall rules) with sqlcmd or telnet.
  2. Check credentials and authentication mode (SQL auth vs Windows auth) in the sink connection string.
  3. Enable/align TLS settings: match Encrypt/trust-server-certificate options between client and server.
  4. Inspect the inner tiberius message with RUST_BACKTRACE=1 or structured logging to identify the exact driver failure.
  5. Confirm the target database and table exist and the user has INSERT permissions.

Example fix

// before: opaque wrapped error
SinkError::SqlServer(anyhow!(err))
// after: log the underlying tiberius error kind for diagnosis
match &err {
    tiberius::error::Error::Io(io) => tracing::error!("sql server io error: {io}"),
    tiberius::error::Error::Server(server) => tracing::error!("sql server rejected: {server}"),
    _ => {}
}
SinkError::SqlServer(anyhow!(err))
Defensive patterns

Strategy: retry

Validate before calling

// before creating the sink: probe SQL Server reachability
use tiberius::{Config, AuthMethod};
let mut cfg = Config::new();
cfg.host(host).port(port).authentication(AuthMethod::sql_server(user, pass));
match tiberius::Client::connect(cfg, tokio::net::TcpStream::connect((host, port)).await?).await {
    Ok(_) => println!("sql server reachable"),
    Err(e) => eprintln!("pre-check failed: {e}"),
}

Try / catch

// match on the tiberius error kind for retry vs fatal decision
match err.downcast_ref::<tiberius::error::Error>() {
    Some(tiberius::error::Error::Io(_)) => retry_with_backoff(),
    Some(tiberius::error::Error::Server(_)) => fatal(),
    _ => fatal(),
}

Prevention

When it happens

Trigger: Any tiberius::error::Error propagated while writing to or connecting to a SQL Server sink: failed TCP/TLS handshake, login failure, query execution failure, or protocol errors during bulk insert.

Common situations: Wrong SQL Server host/port in the connection string, invalid credentials, SQL Server TLS requiring encryption the client cannot negotiate, firewall blocking port 1433, or SQL Server syntax/data-type issues during sink writes.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


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