{"record":{"id":"9b431db25acf00d2","repo":"apache/beam","slug":"duplicate-column-names-duplicates","errorCode":null,"errorMessage":"Duplicate column names: {duplicates}","messagePattern":"Duplicate column names: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/ml/rag/ingestion/spanner.py","lineNumber":435,"sourceCode":"  \"\"\"\n  def __init__(self, table_name: str, column_specs: list[SpannerColumnSpec]):\n    \"\"\"Initialize schema builder.\n    \n    Args:\n        table_name: Table name (used in NamedTuple type name)\n        column_specs: List of column specifications\n    \n    Raises:\n        ValueError: If duplicate column names are found\n    \"\"\"\n    self.table_name = table_name\n    self.column_specs = column_specs\n\n    # Validate no duplicates\n    names = [col.column_name for col in column_specs]\n    duplicates = set(name for name in names if names.count(name) > 1)\n    if duplicates:\n      raise ValueError(f\"Duplicate column names: {duplicates}\")\n\n    # Create NamedTuple type\n    fields = [(col.column_name, col.python_type) for col in column_specs]\n    type_name = f\"SpannerVectorRecord_{table_name}\"\n    self.record_type = NamedTuple(type_name, fields)  # type: ignore\n\n    # Register coder\n    registry.register_coder(self.record_type, RowCoder)\n\n  def create_converter(self) -> Callable[[EmbeddableItem], NamedTuple]:\n    \"\"\"Create converter function from EmbeddableItem to NamedTuple record.\n\n    Returns:\n        Function that converts an EmbeddableItem to a NamedTuple record\n    \"\"\"\n    def convert(embeddable: EmbeddableItem) -> self.record_type:  # type: ignore\n      values = {\n          col.column_name: col.value_fn(embeddable)","sourceCodeStart":417,"sourceCodeEnd":453,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/ml/rag/ingestion/spanner.py#L417-L453","documentation":"SpannerVectorRecord (the writer's table mapping) is built from column_specs, and its NamedTuple record type cannot have two fields with the same name. __init__ scans spec names for duplicates and raises at construction time with the duplicated set.","triggerScenarios":"Building SpannerVectorRecord with a list of SpannerColumnSpec where two specs share column_name — e.g. adding two embedding specs with the same column name, or programmatically merging spec lists that overlap.","commonSituations":"Calling with_embedding_spec twice for the same column; combining default id/content specs with custom specs that repeat a name; joining column lists from multiple sources without deduping.","solutions":["Remove or rename the duplicate spec so each column_name appears once","Dedupe specs before constructing: {spec.column_name: spec for spec in specs}.values()","If two embeddings are needed, use distinct column names (e.g. 'embedding_dense', 'embedding_sparse')"],"exampleFix":"// before\nbuilder.with_embedding_spec('embedding').with_embedding_spec('embedding', convert_fn=f)\n// after\nbuilder.with_embedding_spec('embedding').with_embedding_spec('embedding_v2', convert_fn=f)","handlingStrategy":"validation","validationCode":"names = [c.column_name for c in column_specs]\ndupes = {n for n in names if names.count(n) > 1}\nassert not dupes, f\"Duplicate Spanner columns: {dupes}\"","typeGuard":"def specs_are_unique(specs) -> bool:\n    names = [c.column_name for c in specs]\n    return len(names) == len(set(names))","tryCatchPattern":null,"preventionTips":["Build column specs from a dict keyed by column name to guarantee uniqueness","Don't call with_embedding_spec twice with the same column_name","Dedupe merged spec lists before constructing SpannerVectorRecord"],"tags":["python","spanner","schema","configuration"],"backgroundTag":"schema-validation-failed","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}