risingwavelabs/risingwave · error · SinkError::Config

Turbopuffer namespace must be 1 to 128 bytes

Error message

Turbopuffer namespace must be 1 to 128 bytes

What it means

Turbopuffer namespace names must be between 1 and 128 bytes. validate_namespace enforces this before the sink builds the request URL or validates the connector config (try_from). A non-conforming namespace value in the WITH clause, or in the namespace_column data of a row, raises this error.

Solutions

  1. Set turbopuffer.namespace to a 1–128 byte string in the WITH clause.
  2. Clean the namespace_column data so values are non-empty and ≤128 bytes.
  3. If namespaces come from a column, filter out rows with empty/too-long values before sinking.

Example fix

// before
WITH (connector='turbopuffer', turbopuffer.namespace='', ...)
// after
WITH (connector='turbopuffer', turbopuffer.namespace='my-index-v1', ...)
Defensive patterns

Strategy: validation

Validate before calling

fn namespace_len_ok(ns: &str) -> bool {
    !ns.is_empty() && ns.len() <= 128
}

Prevention

When it happens

Trigger: Setting turbopuffer.namespace to an empty string or a string longer than 128 bytes in the sink WITH options; or a row whose namespace_column value is empty or exceeds 128 bytes, evaluated by url_for_row at write time.

Common situations: Copy-pasting a namespace with trailing whitespace stripped to empty; generating namespaces from data where some values are empty strings; very long auto-generated namespace names.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/10cb6efb70f177aa. Report an issue: GitHub.

Appendix: source

Thrown at src/connector/src/sink/turbopuffer.rs:726

            CompactedOp::Delete => deletes.push(id),
        }
    }
    (upsert_rows, deletes)
}

fn document_id_from_i64(value: i64) -> DocumentId {
    if value < 0 {
        tracing::warn!(
            value,
            "cast negative turbopuffer integer document id to unsigned integer"
        );
    }
    DocumentId::U64(value as u64)
}

fn validate_namespace(namespace: &str) -> Result<()> {
    if namespace.is_empty() || namespace.len() > 128 {
        return Err(SinkError::Config(anyhow!(
            "Turbopuffer namespace must be 1 to 128 bytes"
        )));
    }
    if !namespace
        .bytes()
        .all(|b| b.is_ascii_alphanumeric() || matches!(b, b'-' | b'_' | b'.'))
    {
        return Err(SinkError::Config(anyhow!(
            "Turbopuffer namespace must match [A-Za-z0-9-_.]{{1,128}}"
        )));
    }
    Ok(())
}

fn parse_column_selection(
    value: Option<&str>,
    schema: &Schema,
    attribute_indices: &[usize],

View on GitHub (pinned to 6469eb736d)