influxdata/influxdb · error · Error::DuplicateColumnName
duplicate column name
Error message
duplicate column name: {column} What it means
DuplicateColumnNameSnafu is raised by write_table_batch in mutable_batch_pb when decoding a WriteTableBatch protobuf: two adjacent columns in the batch share the same name. The decoder walks the column list with a 2-wide window and rejects any duplicate, because a table batch must have unique column names to build a valid MutableBatch. The duplicate name is embedded in the message.
Solutions
- Deduplicate columns by name in the client/producer before sending the WriteTableBatch
- Reject or log the payload upstream with the duplicated column name from the error message
- Add a producer-side schema check that tag and field names are distinct per line/row
Example fix
// before
batch.columns.push(col_timestamp);
batch.columns.push(col_timestamp); // duplicate
// after
let seen: HashSet<&str> = HashSet::new();
if !seen.insert(col_timestamp.column_name.as_str()) { /* skip or error */ }
batch.columns.push(col_timestamp); Defensive patterns
Strategy: validation
Validate before calling
fn has_duplicate_columns(names: &[&str]) -> bool {
names.iter().collect::<std::collections::HashSet<_>>().len() != names.len()
}
if has_duplicate_columns(&column_names) { /* reject batch before sending */ } Try / catch
match write_table_batch(batch, table_batch) {
Err(e) if e.to_string().starts_with("duplicate column name") => /* log offending name and reject payload */,
other => other?,
} Prevention
- Deduplicate columns by name on the producer side
- Keep tag and field names distinct per measurement
- Add round-trip encode/decode tests that assert unique column names
When it happens
Trigger: Calling write_table_batch (directly or via decode_database_batch / the write path's run) on a protobuf WriteTableBatch whose `columns` list contains two entries with an identical column_name.
Common situations: A producer bug appending the same column twice when building the LP/protobuf payload; merging two row entries without deduplicating fields; schema drift where a tag and field were given the same name.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- time column must not contain nulls
- table batch must contain time column
- Error converting compaction level
- Error converting max_columns_per_table
- Error converting max_tables
AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19).
Data as JSON: /api/errors/dd48879b7c7361d6.
Report an issue: GitHub.
Appendix: source
Thrown at core/mutable_batch_pb/src/decode.rs:100
if to_insert == 0 {
return Ok(());
}
// Verify columns are unique
let mut columns: Vec<&str> = table_batch
.columns
.iter()
.map(|c| c.column_name.as_str())
.collect();
columns.sort_unstable();
let mut found_time = columns.first().is_some_and(|f| *f == TIME_COLUMN_NAME);
// it would be nice to use `array_windows` here but alas, that's nightly-only
for two_names in columns.windows(2) {
let first = two_names[0];
let second = two_names[1];
ensure!(
first != two_names[1],
DuplicateColumnNameSnafu { column: first }
);
found_time |= second == TIME_COLUMN_NAME;
}
ensure!(found_time, MissingTimeSnafu);
let mut writer = Writer::new(batch, to_insert);
for column in &table_batch.columns {
let influx_type = pb_column_type(column)?;
let valid_mask = compute_valid_mask(&column.null_mask, to_insert);
let valid_mask = valid_mask.as_deref();
// Already verified has values
let values = column.values.as_ref().unwrap();
View on GitHub (pinned to 06200ef96b)