{"record":{"id":"20f07488ebdb2f8e","repo":"risingwavelabs/risingwave","slug":"turbopuffer-attribute-column-must-not-be-named-id","errorCode":null,"errorMessage":"Turbopuffer attribute column must not be named id","messagePattern":"Turbopuffer attribute column must not be named id","errorType":"validation","errorClass":"SinkError::Config","httpStatus":null,"severity":"error","filePath":"src/connector/src/sink/turbopuffer.rs","lineNumber":221,"sourceCode":"            (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\"\n                )));\n            }\n        }\n        let full_text_search_columns = parse_column_selection(\n            config.full_text_search_columns.as_deref(),\n            &schema,\n            &attribute_indices,\n        )?;\n        let filterable_columns = parse_column_selection(\n            config.filterable_columns.as_deref(),\n            &schema,\n            &attribute_indices,\n        )?;\n        let has_vector = attribute_indices\n            .iter()\n            .any(|idx| matches!(schema[*idx].data_type, DataType::Vector(_)));\n        if has_vector && config.distance_metric.is_none() {","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/connector/src/sink/turbopuffer.rs#L203-L239","documentation":"Turbopuffer treats `id` specially in write requests as the document ID, so it cannot be sent as a regular attribute. The sink reserves the primary-key/id column and, in `try_from`, rejects any remaining attribute column literally named `id`.","triggerScenarios":"Creating a Turbopuffer sink whose schema contains a column named `id` that is not the primary key designated for the document ID (it is neither excluded nor used as pk), e.g. an extra `id` varchar column distinct from the pk column.","commonSituations":"Source tables carry their own `id` column while the user also defines a separate pk for the sink; renaming a source column to `id` during schema evolution; copying tables that already have an `id` attribute.","solutions":["Rename the attribute column (e.g. `record_id`, `item_id`) in the materialization feeding the sink.","Make the `id` column the sink's primary key so it is consumed as the document ID instead of an attribute.","Drop the redundant `id` column from the sink schema if it duplicates the pk.","Alias it during SELECT, e.g. `id AS external_id` in the upstream MV."],"exampleFix":"// before\nCREATE SINK s FROM mv WITH (connector='turbopuffer', pk='doc_pk');\n-- mv has both doc_pk (pk) and id (attribute)\n\n// after\nCREATE MATERIALIZED VIEW mv2 AS\nSELECT doc_pk, id AS external_id, ... FROM mv;\nCREATE SINK s FROM mv2 WITH (connector='turbopuffer', pk='doc_pk');","handlingStrategy":"validation","validationCode":"// SQL: ensure no attribute column is literally 'id'\nSELECT name FROM rw_columns WHERE relation = 'mv_for_sink' AND name = 'id';\n// must return no rows unless 'id' is the designated pk","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Rename source `id` columns (e.g. external_id) before sinking to Turbopuffer","Designate `id` as the sink primary key if it should be the document ID","Lint sink schemas for reserved names at deploy time"],"tags":["sink","turbopuffer","config","reserved-column-name"],"backgroundTag":"schema-validation-failed","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"}