influxdata/influxdb · critical

error reading time column

Error message

error reading time column

What it means

partition_keys calls batch.time_column().expect("error reading time column"), panicking when the batch has no time column. Partition key generation always needs timestamp data to render time-based template parts, so a batch lacking the time column is an invariant violation rather than a recoverable error.

Solutions

  1. Ensure the batch includes a valid 'time' column before partitioning
  2. Validate batch schema (time column present and of timestamp type) before calling partition_keys
  3. If building batches manually, always append the time column returned by the write API

Example fix

// before
let keys: Vec<_> = partition_keys(&batch, template.parts()).collect();
// after
assert!(batch.time_column().is_some(), "batch must contain a time column before partitioning");
let keys: Vec<_> = partition_keys(&batch, template.parts()).collect();
Defensive patterns

Strategy: validation

Validate before calling

if batch.time_column().is_none() {
    return Err(anyhow!("batch is missing the required 'time' column; cannot compute partition keys"));
}

Type guard

fn has_time_column(b: &dyn Batch) -> bool { b.time_column().is_some() }

Prevention

When it happens

Trigger: Calling partition_keys/partition_batch on a Batch whose time_column() returns None — i.e. a record batch without a 'time' column or with an unreadable/invalid time column.

Common situations: Feeding a hand-built Arrow RecordBatch into partitioning without a time column; a write path that dropped or renamed the time column upstream; corrupted parquet data missing 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/fce84db081ee4dfe. Report an issue: GitHub.

Appendix: source

Thrown at core/partition/src/lib.rs:83

    }

    range_encode(partition_keys(batch, template.parts()))
}

/// Returns an iterator of partition keys for the given table batch.
///
/// This function performs deduplication on returned keys; the returned iterator
/// yields [`Some`] containing the partition key string when a new key is
/// generated, and [`None`] when the generated key would equal the last key.
pub fn partition_keys<'a, T>(
    batch: &'a T,
    template_parts: impl Iterator<Item = TemplatePart<'a>>,
) -> impl Iterator<Item = Option<Result<String, PartitionKeyError>>> + 'a
where
    T: Batch,
{
    // Extract the timestamp data.
    let time = batch.time_column().expect("error reading time column");

    // Convert TemplatePart into an ordered array of Template
    let mut template = template_parts
        .map(|v| Template::from((v, batch, time)))
        .collect::<Vec<_>>();

    // Track the length of the last yielded partition key, and pre-allocate the
    // next partition key string to match it.
    //
    // In the happy path, keys of consistent sizes are generated and the
    // allocations reach a minimum. If the keys are inconsistent, at best a
    // subset of allocations are eliminated, and at worst, a few bytes of memory
    // is temporarily allocated until the resulting string is shrunk down.
    let mut last_len = 5;

    // The first row in a batch must always be evaluated to produce a key.
    //
    // Row 0 is guaranteed to exist, otherwise attempting to read the time

View on GitHub (pinned to 06200ef96b)