{"record":{"id":"7c7ae8bfd6009d2f","repo":"influxdata/influxdb","slug":"no-duplicate-column","errorCode":null,"errorMessage":"no duplicate column","messagePattern":"no duplicate column","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"influxdb3_catalog/src/catalog/versions/v2/update.rs","lineNumber":1655,"sourceCode":"\n        let id = self.table.tag_columns.next_id();\n        // Only increment if id is less than MAX.\n        if id < TagId::MAX {\n            self.table.tag_columns.set_next_id(id.next())\n        }\n        let col_id = self.next_legacy_column_id()?;\n        let tag_col = Arc::new(TagColumn::new(id, col_id, tag.as_ref()));\n\n        self.table\n            .tag_columns\n            .insert(id, Arc::clone(&tag_col))\n            .expect(\"no duplicate tag\");\n\n        let col_def = ColumnDefinition::Tag(Arc::clone(&tag_col));\n        self.table\n            .columns\n            .insert(col_def.clone())\n            .expect(\"no duplicate column\");\n\n        self.column_definitions.push(col_def.into());\n\n        Ok(tag_col)\n    }\n\n    pub(crate) fn add_time(&mut self) -> Result<Arc<TimestampColumn>> {\n        if self.table.timestamp_column.is_some() {\n            return Err(CatalogError::DuplicateColumn {\n                name: TIME_COLUMN_NAME.into(),\n                existing: InfluxColumnType::Timestamp,\n            });\n        }\n        let col_id = self.next_legacy_column_id()?;\n        let time_col = Arc::new(TimestampColumn::new(col_id, TIME_COLUMN_NAME));\n        self.table.timestamp_column = Some(Arc::clone(&time_col));\n        let col_def = ColumnDefinition::Timestamp(Arc::clone(&time_col));\n        self.table","sourceCodeStart":1637,"sourceCodeEnd":1673,"githubUrl":"https://github.com/influxdata/influxdb/blob/06200ef96ba82c5f6727e5038a83af8e722c6875/influxdb3_catalog/src/catalog/versions/v2/update.rs#L1637-L1673","documentation":"Panic from `.expect(\"no duplicate column\")` after inserting a `ColumnDefinition::Tag` into `self.table.columns`, the table-wide BTreeSet of all columns keyed by (name, type). The update transaction assumes the new tag column's name cannot already be present in `columns`; if it is, the in-memory table definition and its log are out of sync. Like the sibling expects in this file, it signals internal catalog corruption rather than a recoverable API error.","triggerScenarios":"Adding a tag column whose name already exists in the table's columns set — e.g. the same batch or an earlier batch already added a column (tag/field/time) with the same name, or a replayed catalog batch re-inserts an existing tag.","commonSituations":"Replayed WAL/catalog batches after a crash mid-write; merging catalogs from two nodes without deduplication; users running raw catalog APIs to add the same column twice; schema-version mismatch between the persisted log and code.","solutions":["Check for duplicate column definitions in the catalog log for this table; drop or dedupe the duplicate entries.","Ensure create/add-column operations are idempotent or guarded by a pre-check before applying the batch.","Restore the catalog from a backup taken before the corrupting write.","If hit through normal influxdb3 usage, report it as a bug with the offending catalog batch."],"exampleFix":"// before\nself.table.columns.insert(col_def.clone()).expect(\"no duplicate column\");\n// after\nif !self.table.columns.insert(col_def.clone()) {\n    return Err(Error::DuplicateColumnName { table: self.table.name.clone(), column: col_def.name().to_string() });\n}","handlingStrategy":"validation","validationCode":"// Check the target column name is unused before applying an add-column batch\nif table_def.columns().iter().any(|c| c.name() == new_tag_name) {\n    return Ok(()); // already added; treat add as idempotent\n}","typeGuard":"fn column_name_taken(table: &TableDefinition, name: &str) -> bool { table.columns.iter().any(|c| c.name() == name) }","tryCatchPattern":null,"preventionTips":["Make add-column operations idempotent by pre-checking the columns set.","Deduplicate catalog logs after crash recovery before replay.","Avoid merging catalogs from multiple nodes without a dedupe pass."],"tags":["influxdb3","catalog","panic","duplicate-column","internal-state"],"backgroundTag":"internal-invariant-violation","analyzedSha":"06200ef96ba82c5f6727e5038a83af8e722c6875","analyzedAt":"2026-09-19T12:55:30.003Z","contentChangedAt":"2026-09-19T12:55:30.003Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}