influxdata/influxdb · error · Error::MissingTime

table batch must contain time column

Error message

table batch must contain time column

What it means

MissingTimeSnafu is raised by write_table_batch in mutable_batch_pb when a decoded WriteTableBatch contains no `time` column. Every IOx table batch must include the special TIME_COLUMN_NAME ("time") column; the decoder scans all columns (and the windowed pair check) setting found_time when it sees it, and fails with this error if none was present.

Solutions

  1. Ensure the producer always includes a `time` column (the default timestamp) in every batch
  2. If timestamps are named differently, rename the column to `time` before sending
  3. Verify line protocol parsing code maps the timestamp position to the TIME_COLUMN_NAME column

Example fix

// before
columns: [foo]
// after
columns: [foo, time]
// producer:
batch.columns.push(make_time_column(timestamp_ns));
Defensive patterns

Strategy: validation

Validate before calling

fn has_time_column(names: &[&str]) -> bool {
    names.iter().any(|n| *n == "time")
}
if !has_time_column(&column_names) { /* add time column or reject */ }

Try / catch

match write_table_batch(batch, table_batch) {
    Err(e) if e.to_string() == "table batch must contain time column" => /* ensure producer sends `time` */,
    other => other?,
}

Prevention

When it happens

Trigger: Calling write_table_batch / decode_database_batch on a WriteTableBatch protobuf that has field/tag columns but no column named `time`.

Common situations: A client omitting the timestamp field when building line protocol or the protobuf batch; a serializer mapping timestamps to a custom name; partial column filtering that accidentally dropped the time column.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19). Data as JSON: /api/errors/64221811dbcae203. Report an issue: GitHub.

Appendix: source

Thrown at core/mutable_batch_pb/src/decode.rs:108

        .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();

        match influx_type {
            InfluxColumnType::Field(InfluxFieldType::Float) => match valid_mask {
                None => writer.write_f64s_from_slice(&column.column_name, &values.f64_values),
                Some(mask) => writer.write_f64s_from_slice_with_mask(
                    &column.column_name,
                    mask,
                    &values.f64_values,
                ),

View on GitHub (pinned to 06200ef96b)