apache/seatunnel · error · IllegalArgumentException

end_timestamp can't be negative

Error message

end_timestamp can't be negative

What it means

The time-range validation in HbaseClient.applyTimeRange rejects a negative end_timestamp, throwing IllegalArgumentException('end_timestamp can't be negative'). HBase time ranges are epoch millis and must be non-negative. The library fails fast during Scan construction rather than sending an invalid range to the cluster.

Source

Thrown at seatunnel-connectors-v2/connector-hbase/src/main/java/org/apache/seatunnel/connectors/seatunnel/hbase/client/HbaseClient.java:407

            String[] columnNameSplit = columnName.split(":");
            scan.addColumn(Bytes.toBytes(columnNameSplit[0]), Bytes.toBytes(columnNameSplit[1]));
        }
        return scan;
    }

    private static void applyTimeRange(Scan scan, HbaseParameters hbaseParameters)
            throws IOException {
        Long startTimestamp = hbaseParameters.getStartTimestamp();
        Long endTimestamp = hbaseParameters.getEndTimestamp();
        if (startTimestamp == null && endTimestamp == null) {
            return;
        }

        if (startTimestamp != null && startTimestamp < 0) {
            throw new IllegalArgumentException("start_timestamp can't be negative");
        }
        if (endTimestamp != null && endTimestamp < 0) {
            throw new IllegalArgumentException("end_timestamp can't be negative");
        }

        long min = startTimestamp == null ? 0L : startTimestamp;
        long max = endTimestamp == null ? Long.MAX_VALUE : endTimestamp;
        if (min >= max) {
            throw new IllegalArgumentException("start_timestamp must be less than end_timestamp");
        }
        scan.setTimeRange(min, max);
    }

    /**
     * Get a RegionLocator.
     *
     * @param tableName table name (preferably fully qualified as {@code namespace:table})
     * @return RegionLocator
     * @throws IOException exception
     * @deprecated Use {@link #getRegionLocator(String, String)} instead to avoid relying on the
     *     default namespace behavior.

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Set end_timestamp to a valid epoch-millisecond value >= 0
  2. Verify the expression that generates the value in your config or scheduler
  3. Omit end_timestamp to default to Long.MAX_VALUE (no upper bound)

Example fix

// before
end_timestamp = -1
// after
end_timestamp = 1700003600000
Defensive patterns

Strategy: validation

Validate before calling

Long end = config.getEndTimestamp();
if (end != null && end < 0) {
    throw new IllegalArgumentException("end_timestamp must be >= 0 (epoch millis)");
}

Type guard

static boolean validEndTimestamp(Long ts) { return ts == null || ts >= 0; }

Try / catch

try { client.buildScan(params); }
catch (IllegalArgumentException e) {
    if (e.getMessage().contains("end_timestamp")) {
        // correct the config value before resubmitting
    } else throw e;
}

Prevention

When it happens

Trigger: Configuring option end_timestamp with a negative value that reaches buildScan via applyTimeRange.

Common situations: Computing end time as now-minus-offset with a sign error; seconds-vs-millis confusion producing overflow/negatives; placeholder substitution failure.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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