influxdata/influxdb · error
no duplicate column
Error message
no duplicate column
What it means
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.
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.
Example fix
// before
self.table.columns.insert(col_def.clone()).expect("no duplicate column");
// after
if !self.table.columns.insert(col_def.clone()) {
return Err(Error::DuplicateColumnName { table: self.table.name.clone(), column: col_def.name().to_string() });
} Defensive patterns
Strategy: validation
Validate before calling
// Check the target column name is unused before applying an add-column batch
if table_def.columns().iter().any(|c| c.name() == new_tag_name) {
return Ok(()); // already added; treat add as idempotent
} Type guard
fn column_name_taken(table: &TableDefinition, name: &str) -> bool { table.columns.iter().any(|c| c.name() == name) } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- no duplicate tag
- auto field family exists
- column id in series key should be valid
- database should exist by id
- field does not exist
AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19).
Data as JSON: /api/errors/7c7ae8bfd6009d2f.
Report an issue: GitHub.
Appendix: source
Thrown at influxdb3_catalog/src/catalog/versions/v2/update.rs:1655
let id = self.table.tag_columns.next_id();
// Only increment if id is less than MAX.
if id < TagId::MAX {
self.table.tag_columns.set_next_id(id.next())
}
let col_id = self.next_legacy_column_id()?;
let tag_col = Arc::new(TagColumn::new(id, col_id, tag.as_ref()));
self.table
.tag_columns
.insert(id, Arc::clone(&tag_col))
.expect("no duplicate tag");
let col_def = ColumnDefinition::Tag(Arc::clone(&tag_col));
self.table
.columns
.insert(col_def.clone())
.expect("no duplicate column");
self.column_definitions.push(col_def.into());
Ok(tag_col)
}
pub(crate) fn add_time(&mut self) -> Result<Arc<TimestampColumn>> {
if self.table.timestamp_column.is_some() {
return Err(CatalogError::DuplicateColumn {
name: TIME_COLUMN_NAME.into(),
existing: InfluxColumnType::Timestamp,
});
}
let col_id = self.next_legacy_column_id()?;
let time_col = Arc::new(TimestampColumn::new(col_id, TIME_COLUMN_NAME));
self.table.timestamp_column = Some(Arc::clone(&time_col));
let col_def = ColumnDefinition::Timestamp(Arc::clone(&time_col));
self.tableView on GitHub (pinned to 06200ef96b)