{"record":{"id":"3f4e1b20a0ce078b","repo":"risingwavelabs/risingwave","slug":"turbopuffer-sink-requires-either-namespace-or-name","errorCode":null,"errorMessage":"Turbopuffer sink requires either namespace or namespace_column","messagePattern":"Turbopuffer sink requires either namespace or namespace_column","errorType":"validation","errorClass":"SinkError::Config","httpStatus":null,"severity":"error","filePath":"src/connector/src/sink/turbopuffer.rs","lineNumber":204,"sourceCode":"                            \"Turbopuffer namespace_column '{}' not found in sink schema\",\n                            namespace_column\n                        ))\n                    })?;\n                if schema[index].data_type != DataType::Varchar {\n                    return Err(SinkError::Config(anyhow!(\n                        \"Turbopuffer namespace_column must be varchar, got {:?}\",\n                        schema[index].data_type\n                    )));\n                }\n                TurbopufferNamespace::Dynamic { index }\n            }\n            (Some(_), Some(_)) => {\n                return Err(SinkError::Config(anyhow!(\n                    \"Turbopuffer sink requires only one of namespace or namespace_column\"\n                )));\n            }\n            (None, None) => {\n                return Err(SinkError::Config(anyhow!(\n                    \"Turbopuffer sink requires either namespace or namespace_column\"\n                )));\n            }\n        };\n\n        // Turbopuffer treats `id` as the document ID in write requests; it is not a schema\n        // attribute. Dynamic namespace is also metadata for routing, not a document attribute.\n        let excluded_indices = match &namespace {\n            TurbopufferNamespace::Static(_) => HashSet::from([pk_index]),\n            TurbopufferNamespace::Dynamic { index } => HashSet::from([pk_index, *index]),\n        };\n        let attribute_indices = (0..schema.len())\n            .filter(|idx| !excluded_indices.contains(idx))\n            .collect_vec();\n        for index in &attribute_indices {\n            if schema[*index].name == \"id\" {\n                return Err(SinkError::Config(anyhow!(\n                    \"Turbopuffer attribute column must not be named id\"","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/connector/src/sink/turbopuffer.rs#L186-L222","documentation":"The Turbopuffer sink must know which namespace each document is written to, so exactly one of the static `namespace` option or the per-row `namespace_column` option must be provided. In `try_from`, the (None, None) arm rejects sinks that provide neither.","triggerScenarios":"Creating a Turbopuffer sink with neither `namespace` nor `namespace_column` in the WITH options.","commonSituations":"Omitting namespace options from copied config; assuming turbopuffer derives a namespace from the table name; partial template rendering that dropped the namespace key.","solutions":["Add `namespace = '<name>'` to the WITH options for a fixed namespace.","Add `namespace_column = '<varchar col>'` for per-row namespaces.","Re-check the sink creation statement against the Turbopuffer sink docs."],"exampleFix":"// before\nWITH (connector = 'turbopuffer', access_key = '...');\n\n// after\nWITH (connector = 'turbopuffer', access_key = '...', namespace = 'docs');","handlingStrategy":"validation","validationCode":"if (!withClause.namespace && !withClause.namespace_column) {\n  throw new Error('turbopuffer sink needs namespace or namespace_column');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use a config template/checklist that always includes one namespace option","Validate sink options against the connector's required-option list before creation"],"tags":["sink","turbopuffer","config","missing-option"],"backgroundTag":"missing-required-config-field","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}