{"record":{"id":"d281e70c9b0469b6","repo":"risingwavelabs/risingwave","slug":"max-linger-second-must-be-greater-than-0","errorCode":null,"errorMessage":"`max_linger_second` must be greater than 0","messagePattern":"`max_linger_second` must be greater than 0","errorType":"validation","errorClass":"SinkError::Config","httpStatus":null,"severity":"error","filePath":"src/connector/src/sink/turbopuffer.rs","lineNumber":107,"sourceCode":"impl EnforceSecret for TurbopufferConfig {\n    const ENFORCE_SECRET_PROPERTIES: phf::Set<&'static str> = phf::phf_set! {\n        \"api_key\",\n    };\n}\n\nimpl TurbopufferConfig {\n    fn from_btreemap(values: BTreeMap<String, String>) -> Result<Self> {\n        let config = serde_json::from_value::<TurbopufferConfig>(\n            serde_json::to_value(values).expect(\"serialize sink properties\"),\n        )\n        .map_err(|e| SinkError::Config(anyhow!(e)))?;\n        if config.write_batch_size == 0 {\n            return Err(SinkError::Config(anyhow!(\n                \"`write_batch_size` must be greater than 0\"\n            )));\n        }\n        if config.max_linger_second == 0 {\n            return Err(SinkError::Config(anyhow!(\n                \"`max_linger_second` must be greater than 0\"\n            )));\n        }\n        if config.num_shards == Some(0) {\n            return Err(SinkError::Config(anyhow!(\n                \"`num_shards` must be greater than 0\"\n            )));\n        }\n        Ok(config)\n    }\n}\n\n#[derive(Clone, Debug)]\nenum TurbopufferNamespace {\n    Static(String),\n    Dynamic { index: usize },\n}\n","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/connector/src/sink/turbopuffer.rs#L89-L125","documentation":"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.","triggerScenarios":"CREATE SINK with connector='turbopuffer' and WITH option max_linger_second = '0'.","commonSituations":"Placeholder value left as 0; attempts to 'disable' lingering by setting 0 instead of omitting the option.","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"],"exampleFix":"// before\nWITH (connector='turbopuffer', max_linger_second = '0')\n// after\nWITH (connector='turbopuffer', max_linger_second = '1')","handlingStrategy":"validation","validationCode":"if (props.max_linger_second !== undefined && Number(props.max_linger_second) <= 0) throw new Error('max_linger_second must be > 0')","typeGuard":"const validLinger = (n) => Number.isInteger(n) && n > 0;","tryCatchPattern":"catch (SinkError::Config(e)) if e.contains('max_linger_second') { set a positive value and retry }","preventionTips":["Use small positive values for low latency, never 0","Review config templates for placeholder zeros","Document the option's constraints"],"tags":["turbopuffer","config","validation","lingering"],"backgroundTag":"invalid-config-value","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}