databendlabs/databend · error

Unsupported unit

Error message

Unsupported unit: {}

What it means

In eval_timestamp_between (src/query/functions/src/scalars/timestamp/src/date_arithmetic.rs:616), the computed microsecond difference is divided by a unit-specific divisor for exactly three accepted units: "hours", "minutes", "seconds". Any other unit string reaches `unreachable!("Unsupported unit: {}", unit)`. The invariant is that only these three unit names ever flow into this helper.

Solutions

  1. Add a match arm for the unit you need (e.g. "days" => micros / (24 * 3600 * MICROS_PER_SEC)).
  2. Ensure only units this function supports are routed here; map other units to a different implementation upstream.
  3. Replace unreachable!() with a returned error/ErrorCode so unsupported units surface as a clean query error instead of a panic.
  4. Add a unit test per supported unit string.

Example fix

// before
_ => unreachable!("Unsupported unit: {}", unit),
// after
"days" => micros / (24 * 3600 * MICROS_PER_SEC),
other => return Err(ErrorCode::BadArguments(format!("Unsupported unit: {}", other))),
Defensive patterns

Strategy: validation

Validate before calling

fn validate_date_unit(unit: &str) -> Result<(), String> {
    match unit {
        "hours" | "minutes" | "seconds" => Ok(()),
        other => Err(format!("unsupported unit: {}", other)),
    }
}

Try / catch

// Normalize/whitelist user-supplied units before date arithmetic:
let unit = normalize_unit(user_unit)?; // maps DAY->hours-level handling elsewhere
if !matches!(unit, "hours" | "minutes" | "seconds") {
    return Err(ErrorCode::BadArguments(format!("Unsupported unit: {}", unit)));
}

Prevention

When it happens

Trigger: Invoking the timestamp-between evaluation path with a unit string other than "hours", "minutes", or "seconds" — e.g. extending the timestamp_diff family with new units (days, weeks) and routing them into this helper, or binding a user-supplied unit argument directly.

Common situations: A developer adds "days" or "milliseconds" support to date arithmetic and wires it into this helper without adding a match arm; a caller passes a user-provided TIMESTAMPDIFF-style unit straight through instead of converting.

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 databendlabs/databend@288d84d76e (2026-09-11). Data as JSON: /api/errors/cde93798d99f0ea0. Report an issue: GitHub.

Appendix: source

Thrown at src/query/functions/src/scalars/timestamp/src/date_arithmetic.rs:616

        let date_start = date_start / (MICROS_PER_SEC * factor);
        let date_end = date_end / (MICROS_PER_SEC * factor);
        date_end - date_start
    }

    fn eval_timestamp_between(unit: &str, start: i64, end: i64) -> i64 {
        if start == end {
            return 0;
        }
        if start > end {
            return -Self::eval_timestamp_between(unit, end, start);
        }

        let micros = end - start;
        match unit {
            "hours" => micros / (3600 * MICROS_PER_SEC),
            "minutes" => micros / (60 * MICROS_PER_SEC),
            "seconds" => micros / MICROS_PER_SEC,
            _ => unreachable!("Unsupported unit: {}", unit),
        }
    }
}

pub(super) fn register(registry: &mut FunctionRegistry) {
    register_add_functions(registry);
    register_sub_functions(registry);
    register_diff_functions(registry);
    register_between_functions(registry);
}

fn scale_delta(delta: i64, multiplier: i64) -> Result<i64, String> {
    delta
        .checked_mul(multiplier)
        .ok_or_else(|| "Invalid date: interval arithmetic overflow".to_string())
}

fn push_result<T: Default>(result: Result<T, String>, output: &mut Vec<T>, ctx: &mut EvalContext) {

View on GitHub (pinned to 288d84d76e)