risingwavelabs/risingwave · error · SinkError::Config
`max_linger_second` must be greater than 0
Error message
`max_linger_second` must be greater than 0
What it means
Validation guard in TurbopufferConfig::from_btreemap that rejects sink property sets where max_linger_second is 0. A zero linger interval is meaningless for micro-batching and would make batch flushing degenerate, so creating a Turbopuffer sink with `max_linger_second`='0' fails during sink creation.
Solutions
- Set max_linger_second to a positive value (e.g. 1 or more)
- Remove the option to use the sink default
- If lower latency is desired, keep a small positive value rather than 0
Example fix
// before WITH (connector='turbopuffer', max_linger_second = '0') // after WITH (connector='turbopuffer', max_linger_second = '1')
Defensive patterns
Strategy: validation
Validate before calling
if (props.max_linger_second !== undefined && Number(props.max_linger_second) <= 0) throw new Error('max_linger_second must be > 0') Type guard
const validLinger = (n) => Number.isInteger(n) && n > 0;
Try / catch
catch (SinkError::Config(e)) if e.contains('max_linger_second') { set a positive value and retry } Prevention
- Use small positive values for low latency, never 0
- Review config templates for placeholder zeros
- Document the option's constraints
When it happens
Trigger: CREATE SINK with connector='turbopuffer' and WITH option max_linger_second = '0'.
Common situations: Placeholder value left as 0; attempts to 'disable' lingering by setting 0 instead of omitting the option.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- `num_shards` must be greater than 0
- `write_batch_size` must be greater than 0
- `checkpoint_read_chunk_size` must be greater than 0
- `checkpoint_read_max_in_flight_chunks` must be greater than…
- `commit_checkpoint_interval` must be greater than 0
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/d281e70c9b0469b6.
Report an issue: GitHub.
Appendix: source
Thrown at src/connector/src/sink/turbopuffer.rs:107
impl EnforceSecret for TurbopufferConfig {
const ENFORCE_SECRET_PROPERTIES: phf::Set<&'static str> = phf::phf_set! {
"api_key",
};
}
impl TurbopufferConfig {
fn from_btreemap(values: BTreeMap<String, String>) -> Result<Self> {
let config = serde_json::from_value::<TurbopufferConfig>(
serde_json::to_value(values).expect("serialize sink properties"),
)
.map_err(|e| SinkError::Config(anyhow!(e)))?;
if config.write_batch_size == 0 {
return Err(SinkError::Config(anyhow!(
"`write_batch_size` must be greater than 0"
)));
}
if config.max_linger_second == 0 {
return Err(SinkError::Config(anyhow!(
"`max_linger_second` must be greater than 0"
)));
}
if config.num_shards == Some(0) {
return Err(SinkError::Config(anyhow!(
"`num_shards` must be greater than 0"
)));
}
Ok(config)
}
}
#[derive(Clone, Debug)]
enum TurbopufferNamespace {
Static(String),
Dynamic { index: usize },
}
View on GitHub (pinned to 6469eb736d)