risingwavelabs/risingwave · error · SinkError::Http
Turbopuffer namespace_column cannot be null
Error message
Turbopuffer namespace_column cannot be null
What it means
When the namespace is chosen per row via `namespace_column`, the URL for each write is built from that column's value in `url_for_row`. If the datum at the namespace index is NULL at write time, there is no namespace to route the document to, so an Http error is returned for the chunk.
Source
Thrown at src/connector/src/sink/turbopuffer.rs:499
row_encoder,
write_batch_size,
max_linger,
pending_batches: BTreeMap::new(),
})
}
fn url_for_row(&self, row: &impl Row) -> Result<String> {
match &self.namespace {
TurbopufferNamespace::Static(namespace) => Ok(format!(
"{}/v2/namespaces/{}",
self.base_url,
namespace.as_str()
)),
TurbopufferNamespace::Dynamic { index } => {
let namespace = match row.datum_at(*index) {
Some(ScalarRefImpl::Utf8(namespace)) => namespace,
None => {
return Err(SinkError::Http(anyhow!(
"Turbopuffer namespace_column cannot be null"
)));
}
Some(_) => {
return Err(SinkError::Http(anyhow!(
"unexpected namespace_column type, expected varchar"
)));
}
};
validate_namespace(namespace)?;
Ok(format!("{}/v2/namespaces/{}", self.base_url, namespace))
}
}
}
// Turbopuffer document IDs are unsigned 64-bit integers, UUIDs, or strings up to 64 bytes.
// RisingWave UUID IDs can be represented with varchar.
fn id_for_row(&self, row: &impl Row) -> Result<DocumentId> {View on GitHub (pinned to 6469eb736d)
Solutions
- Make the namespace column NOT NULL in the upstream MV/table (e.g. COALESCE(ns, 'default')).
- Backfill existing NULL rows with a default namespace before enabling the sink.
- Add a WHERE filter upstream to exclude rows with NULL namespace.
- If a single namespace works, switch to the static `namespace` option.
Example fix
// before CREATE MATERIALIZED VIEW mv AS SELECT tenant_id::varchar AS ns, * FROM t; // after CREATE MATERIALIZED VIEW mv AS SELECT COALESCE(tenant_id::varchar, 'default') AS ns, * FROM t;
Defensive patterns
Strategy: validation
Validate before calling
// SQL: detect NULL namespaces before the sink processes them SELECT count(*) FROM mv_for_sink WHERE ns IS NULL; -- should be 0
Type guard
// in a row-processing pipeline, before building the sink payload
function getNamespace(row) {
const ns = row.ns;
if (typeof ns !== 'string') throw new TypeError('namespace_column must be a non-null string');
return ns;
} Try / catch
// route failing rows to a dead-letter path
try {
await sink.write(row);
} catch (e) {
if (String(e).includes('namespace_column cannot be null')) {
deadLetter.push({ row, reason: 'null-namespace' });
} else { throw e; }
} Prevention
- Declare namespace columns NOT NULL with COALESCE defaults
- Filter NULL-namespace rows out of the MV feeding the sink
When it happens
Trigger: Writing a row where the varchar namespace_column is NULL; rows inserted with an unspecified namespace column after the sink was created.
Common situations: Nullable namespace column in the MV feeding the sink; batch backfills that omit the namespace field; LEFT JOIN results producing NULL namespaces for unmatched rows.
Related errors
- Turbopuffer document id column cannot be null
- Turbopuffer string document id exceeds 64 bytes
- Google Pub/Sub sink error: missing value to publish
- Turbopuffer sink requires exactly one primary_key column
- Turbopuffer namespace_column must be varchar, got {:?}
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/be26efa6cbdd7de9.
Report an issue: GitHub.