apache/seatunnel · warning

The timestamp_tz column

Error message

The timestamp_tz column {} type datetimeoffset({}) is out of range, which exceeds the maximum scale of {}, it will be converted to datetimeoffset({})

What it means

A TIMESTAMP_TZ column (mapped to SQL Server DATETIMEOFFSET) has a scale above the maximum DATETIMEOFFSET precision (MAX_TIMESTAMP_SCALE, 7). reconvert clamps it and logs a warning that the stored type has reduced fractional precision.

Solutions

  1. Set the timestamp_tz column scale to <= 7 in the schema.
  2. Drop extra precision upstream via a transform (truncate fractional seconds).
  3. Accept the warning if 100ns precision is sufficient.

Example fix

// before
field = { name = "updated_at", type = "timestamp_tz(9)" }
// after
field = { name = "updated_at", type = "timestamp_tz(7)" }
Defensive patterns

Strategy: validation

Validate before calling

if (tzScale > 7) log.warn("datetimeoffset scale {} exceeds max 7; will be clamped", tzScale);

Type guard

boolean fitsSqlServerDatetimeOffset(Integer scale) { return scale == null || scale <= 7; }

Prevention

When it happens

Trigger: reconvert converts a TIMESTAMP_TZ column with scale > 7, e.g. from nanosecond-precision timezone-aware sources.

Common situations: Replicating timestamptz(9)-style columns from PostgreSQL or other engines into SQL Server DATETIMEOFFSET.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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

Appendix: source

Thrown at seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/internal/dialect/sqlserver/SqlServerTypeConverter.java:490

                                column.getScale(),
                                MAX_TIMESTAMP_SCALE,
                                timestampScale);
                    }
                    builder.columnType(
                            String.format("%s(%s)", SQLSERVER_DATETIME2, timestampScale));
                    builder.scale(timestampScale);
                } else {
                    builder.columnType(SQLSERVER_DATETIME2);
                }
                builder.dataType(SQLSERVER_DATETIME2);
                break;
            case TIMESTAMP_TZ:
                // LTZ: maps to DATETIMEOFFSET
                if (column.getScale() != null && column.getScale() > 0) {
                    int timestampTzScale = column.getScale();
                    if (timestampTzScale > MAX_TIMESTAMP_SCALE) {
                        timestampTzScale = MAX_TIMESTAMP_SCALE;
                        log.warn(
                                "The timestamp_tz column {} type datetimeoffset({}) is out of"
                                        + " range, which exceeds the maximum scale of {}, "
                                        + "it will be converted to datetimeoffset({})",
                                column.getName(),
                                column.getScale(),
                                MAX_TIMESTAMP_SCALE,
                                timestampTzScale);
                    }
                    builder.columnType(
                            String.format("%s(%s)", SQLSERVER_DATETIMEOFFSET, timestampTzScale));
                    builder.scale(timestampTzScale);
                } else {
                    builder.columnType(SQLSERVER_DATETIMEOFFSET);
                }
                builder.dataType(SQLSERVER_DATETIMEOFFSET);
                break;
            default:
                throw CommonError.convertToConnectorTypeError(

View on GitHub (pinned to cf67b549a7)