apache/seatunnel · error · java.lang.IllegalArgumentException

Unsupported Timestamp unit: ${unit}

Error message

Unsupported Timestamp unit: ${unit}

What it means

TimestampTypeWriter.writeToVector only handles the Arrow timestamp units it explicitly implements (SEC/MILLI etc.); any other TimeStamp unit (e.g. MICRO, NANO with an unhandled branch) falls through to this IllegalArgumentException. The unit comes from the Arrow field's TimeStamp type, which is derived from the declared SeaTunnel schema/column type.

Source

Thrown at seatunnel-connectors-v2/connector-lance/src/main/java/org/apache/seatunnel/connectors/seatunnel/lance/sink/writers/TimestampTypeWriter.java:58

        long epochMicro = convertToEpochMicro(value);
        TimeUnit unit = timestampType.getUnit();
        String timezone = timestampType.getTimezone();

        if (unit == TimeUnit.MICROSECOND) {
            if (timezone != null && !timezone.isEmpty()) {
                ((TimeStampMicroTZVector) vector).setSafe(rowIndex, epochMicro);
            } else {
                ((TimeStampMicroVector) vector).setSafe(rowIndex, epochMicro);
            }
        } else if (unit == TimeUnit.MILLISECOND) {
            long epochMilli = epochMicro / 1000;
            if (timezone != null && !timezone.isEmpty()) {
                ((TimeStampMilliTZVector) vector).setSafe(rowIndex, epochMilli);
            } else {
                ((TimeStampMilliVector) vector).setSafe(rowIndex, epochMilli);
            }
        } else {
            throw new IllegalArgumentException("Unsupported Timestamp unit: " + unit);
        }
    }

    @Override
    public void writeToListWriter(
            UnionListWriter writer, ArrowType arrowType, Object value, BufferAllocator allocator) {
        ArrowType.Timestamp timestampType = (ArrowType.Timestamp) arrowType;
        long epochMicro = convertToEpochMicro(value);
        TimeUnit unit = timestampType.getUnit();
        if (unit == TimeUnit.MICROSECOND) {
            writer.writeTimeStampMicro(epochMicro);
        } else if (unit == TimeUnit.MILLISECOND) {
            writer.writeTimeStampMilli(epochMicro / 1000);
        }
    }

    @Override
    public void writeToMapKey(

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Coerce the column to millisecond precision in the pipeline (e.g. cast timestamp to TIMESTAMP(3)) so Arrow uses TimeStampMilli, which is supported.
  2. Check which Arrow TimeStampUnit the field has (print field.getType()) and confirm it is one the writer handles (SECOND/MILLI).
  3. Add a branch for the missing unit (TimeStampMicroVector / TimeStampNanoVector with setSafe of the corresponding epoch value) if you maintain a fork.
  4. Verify the source-to-SeaTunnel type mapping isn't silently producing TIMESTAMP(6)/(9); cast at the source instead.

Example fix

// before: nano-precision column
columns = "ts timestamp(9)"

// after: millisecond precision
columns = "ts timestamp(3)"  // maps to supported TimeStampMilli
Defensive patterns

Strategy: validation

Validate before calling

// Java: verify the arrow timestamp unit before writing
ArrowType t = field.getType();
if (t instanceof ArrowType.Timestamp) {
    ArrowType.Timestamp ts = (ArrowType.Timestamp) t;
    if (ts.getUnit() != ArrowType.TimestampUnit.SECOND
            && ts.getUnit() != ArrowType.TimestampUnit.MILLISECOND) {
        throw new IllegalArgumentException("Unsupported unit: " + ts.getUnit());
    }
}

Type guard

boolean isSupportedTimestamp(ArrowType t) {
    if (!(t instanceof ArrowType.Timestamp)) return false;
    ArrowType.TimestampUnit u = ((ArrowType.Timestamp) t).getUnit();
    return u == ArrowType.TimestampUnit.SECOND || u == ArrowType.TimestampUnit.MILLISECOND;
}

Try / catch

try {
    timestampWriter.writeToVector(vector, arrowType, value, rowIndex, allocator);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("Unsupported Timestamp unit")) {
        throw new IllegalStateException("Cast column to timestamp(3) before writing to Lance", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: A Lance sink column resolves to an Arrow TimeStamp with a unit not covered by the if/else chain in writeToVector — e.g. TIMESTAMP with nanosecond or microsecond precision mapped to an Arrow TimeStampUnit the writer lacks a branch for.

Common situations: Source data with micro/nano precision timestamps (e.g. from protobuf, pandas, or JDBC) where schema translation picks a finer Arrow unit than the writer supports; timezone-aware timestamp columns interacting with unit selection.

Related errors


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/e6c78e35a2b8577c. Report an issue: GitHub.