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

  1. Check for duplicate column definitions in the catalog log for this table; drop or dedupe the duplicate entries.
  2. Ensure create/add-column operations are idempotent or guarded by a pre-check before applying the batch.
  3. Restore the catalog from a backup taken before the corrupting write.
  4. 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

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


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.table

View on GitHub (pinned to 06200ef96b)