risingwavelabs/risingwave · error · SinkError::SqlServer
too many column {}
Error message
too many column {} What it means
SQL Server writes via Tiberius are limited to TIBERIUS_PARAM_MAX parameters per operation; each row consumes params_per_op parameters. If even one row would exceed that limit (so the computed batch size floors to 0), the sink cannot proceed and raises this SqlServer error.
Source
Thrown at src/connector/src/sink/sqlserver.rs:148
}
}
impl SqlServerSink {
pub fn new(
mut config: SqlServerConfig,
schema: Schema,
pk_indices: Vec<usize>,
is_append_only: bool,
) -> Result<Self> {
// Rewrite config because tiberius allows a maximum of 2100 params in one query request.
const TIBERIUS_PARAM_MAX: usize = 2000;
let params_per_op = schema.fields().len();
let tiberius_max_batch_rows = if params_per_op == 0 {
config.max_batch_rows
} else {
((TIBERIUS_PARAM_MAX as f64 / params_per_op as f64).floor()) as usize
};
if tiberius_max_batch_rows == 0 {
return Err(SinkError::SqlServer(anyhow!(format!(
"too many column {}",
params_per_op
))));
}
config.max_batch_rows = std::cmp::min(config.max_batch_rows, tiberius_max_batch_rows);
Ok(Self {
config,
schema,
pk_indices,
is_append_only,
})
}
}
impl TryFrom<SinkParam> for SqlServerSink {
type Error = SinkError;
fn try_from(param: SinkParam) -> std::result::Result<Self, Self::Error> {View on GitHub (pinned to 6469eb736d)
Solutions
- Reduce the number of columns sunk (drop or combine columns, e.g. serialize struct columns to a single string)
- Sink into multiple narrower SQL Server tables
- Increase TIBERIUS_PARAM_MAX handling by lowering params_per_op (not possible without code change) — or split the sink
Example fix
// before CREATE SINK s INTO sqlserver ... AS SELECT * FROM wide_mv; -- 700 columns // after CREATE SINK s INTO sqlserver ... AS SELECT id, a, b, c FROM wide_mv; -- narrow projection
Defensive patterns
Strategy: validation
Validate before calling
const TIBERIUS_PARAM_MAX: usize = 2100;
fn check_width(num_columns: usize, params_per_column: usize) -> Result<(), String> {
let params_per_op = num_columns * params_per_column;
if params_per_op == 0 || params_per_op >= TIBERIUS_PARAM_MAX {
Err(format!("{} cols * {} params too wide for SQL Server (max {} params)", num_columns, params_per_column, TIBERIUS_PARAM_MAX))
} else { Ok(()) }
} Try / catch
match create_sqlserver_sink(cfg) {
Err(e) if e.to_string().contains("too many column") => split_sink_into_narrower_tables(),
other => other,
} Prevention
- Keep sunk table column counts modest (well under ~500)
- Prefer serializing nested/struct columns to one string column
- Estimate params-per-row (insert + upsert params) before creating wide sinks
When it happens
Trigger: Calling SqlServerSink::new (via SinkWriterV1Adapter / sink creation) for a table whose column count is so large that params_per_op >= TIBERIUS_PARAM_MAX, making tiberius_max_batch_rows == 0.
Common situations: Very wide tables (hundreds of columns) being sunk to SQL Server; each column needs multiple params (e.g. INSERT plus upsert MERGE params) blowing past the ~2100 TDS parameter limit.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- {e}
- `{}` must be {}, or {}
- Primary key not defined for upsert SQL Server sink (please d
- column {} not found in the downstream SQL Server table {}
- column {} specified in primary_key mismatches with the downs
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/cce2f2ae41458b37.
Report an issue: GitHub.