risingwavelabs/risingwave · error · SinkError::Config
Turbopuffer sink requires only one of namespace or namespace
Error message
Turbopuffer sink requires only one of namespace or namespace_column
What it means
The Turbopuffer sink accepts the namespace either as a static literal (`namespace`) or dynamically per row (`namespace_column`), but not both. In `try_from`, the (Some, Some) arm of the namespace match rejects sinks that specify both options together.
Source
Thrown at src/connector/src/sink/turbopuffer.rs:199
.fields()
.iter()
.position(|field| field.name == *namespace_column)
.ok_or_else(|| {
SinkError::Config(anyhow!(
"Turbopuffer namespace_column '{}' not found in sink schema",
namespace_column
))
})?;
if schema[index].data_type != DataType::Varchar {
return Err(SinkError::Config(anyhow!(
"Turbopuffer namespace_column must be varchar, got {:?}",
schema[index].data_type
)));
}
TurbopufferNamespace::Dynamic { index }
}
(Some(_), Some(_)) => {
return Err(SinkError::Config(anyhow!(
"Turbopuffer sink requires only one of namespace or namespace_column"
)));
}
(None, None) => {
return Err(SinkError::Config(anyhow!(
"Turbopuffer sink requires either namespace or namespace_column"
)));
}
};
// Turbopuffer treats `id` as the document ID in write requests; it is not a schema
// attribute. Dynamic namespace is also metadata for routing, not a document attribute.
let excluded_indices = match &namespace {
TurbopufferNamespace::Static(_) => HashSet::from([pk_index]),
TurbopufferNamespace::Dynamic { index } => HashSet::from([pk_index, *index]),
};
let attribute_indices = (0..schema.len())
.filter(|idx| !excluded_indices.contains(idx))View on GitHub (pinned to 6469eb736d)
Solutions
- Remove the `namespace` option and keep `namespace_column` if namespaces vary per row.
- Remove the `namespace_column` option and keep the static `namespace` if one namespace is enough.
- Review the final WITH clause with SHOW SINK / the catalog to ensure only one namespace option remains.
Example fix
// before WITH ( connector = 'turbopuffer', namespace = 'docs', namespace_column = 'ns' ) // after WITH ( connector = 'turbopuffer', namespace_column = 'ns' )
Defensive patterns
Strategy: validation
Validate before calling
// Ensure only one namespace option appears in the WITH clause
const opts = ['namespace', 'namespace_column'];
if (opts.filter(o => withClause[o] != null).length > 1) throw new Error('specify only one of namespace / namespace_column'); Prevention
- Treat namespace and namespace_column as mutually exclusive in your sink tooling
- Review the generated WITH clause before submitting CREATE SINK
When it happens
Trigger: Creating a Turbopuffer sink whose WITH options include both `namespace = 'x'` and `namespace_column = 'col'`.
Common situations: Merging config snippets from two examples; adding namespace_column to an existing sink that already had a static namespace; templated sink definitions that inject both keys.
Related errors
- Turbopuffer namespace_column must be varchar, got {:?}
- Turbopuffer sink requires either namespace or namespace_colu
- Turbopuffer attribute column must not be named id
- Turbopuffer sink requires distance_metric when sink schema c
- Turbopuffer sink can only be created with sink_decouple enab
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/4e848b7c86734813.
Report an issue: GitHub.