apache/seatunnel · error · SeaTunnelException
Cannot convert timestamp to SCN. Make sure the specified…
Error message
Cannot convert timestamp to SCN. Make sure the specified timestamp is valid.
What it means
OracleConnectionUtils.timestampToScn converts a timestamp to an SCN using Oracle's TIMESTAMP_TO_SCN function and throws SeaTunnelException if the query returns no row, meaning no SCN could be associated with the given timestamp. Oracle cannot map timestamps outside the range retained by its SCN-to-time mapping (bounded by undo/flashback and database uptime).
Solutions
- Use a more recent timestamp within Oracle's SCN mapping retention (typically only hours to a few days)
- Use startup.mode=latest or initial instead of timestamp for old starting points
- Align serverTimeZone config with the Oracle server time zone
- Check DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER availability and flashback configuration
Example fix
// before scan.startup.mode = timestamp scan.startup.timestamp = 1724000000000 // weeks old -> no SCN mapping // after scan.startup.mode = latest
Defensive patterns
Strategy: validation
Validate before calling
long minBack = System.currentTimeMillis() - Duration.ofHours(1).toMillis();
if (timestamp <= 0 || timestamp > System.currentTimeMillis() || timestamp < minBack) {
throw new IllegalArgumentException("timestamp outside SCN-mapping range; use a recent timestamp or startup.mode=latest");
} Try / catch
try {
RedoLogOffset off = OracleConnectionUtils.timestampToScn(conn, ts, tz);
} catch (SeaTunnelException e) {
LOG.warn("No SCN for timestamp {}; fall back to latest", ts);
// fallback: use currentRedoLogOffset(conn)
} Prevention
- Only use timestamps within Oracle's SCN-time mapping retention
- Prefer initial/latest startup modes for old starting points
- Match serverTimeZone config to the DB server time zone
- Avoid choosing timestamps from before a database restart
When it happens
Trigger: Calling timestampToScn with a timestamp too old (beyond the SCN time mapping retention), a future timestamp, or a timestamp in the wrong time zone so the mapping query yields no result.
Common situations: startup.mode=timestamp with start time days/weeks in the past; recently restarted database losing older SCN-time mappings; time zone mismatch between configured serverTimeZone and actual DB time zone.
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
- Convert timestamp to redoLog offset error
- Failed to convert timestamp to SCN
- Cannot read the redo log position via 'SELECT CURRENT_SCN…
- not supported create new Offset by filename and position.
- Read the redoLog offset error
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/203d9ee18bfa06b7.
Report an issue: GitHub.
Appendix: source
Thrown at seatunnel-connectors-v2/connector-cdc/connector-cdc-oracle/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/oracle/utils/OracleConnectionUtils.java:121
"Converting timestamp {} to SCN with server time zone {}",
timestampMs,
effectiveServerTimeZone);
String sql = "SELECT TIMESTAMP_TO_SCN(?) AS SCN FROM DUAL";
return jdbc.prepareQueryAndMap(
sql,
statement -> {
java.sql.Timestamp timestamp = new java.sql.Timestamp(timestampMs);
Calendar calendar =
Calendar.getInstance(TimeZone.getTimeZone(effectiveServerTimeZone));
statement.setTimestamp(1, timestamp, calendar);
},
rs -> {
if (rs.next()) {
final String scn = rs.getString(1);
LOG.info("Converted timestamp {} to SCN: {}", timestampMs, scn);
return new RedoLogOffset(Scn.valueOf(scn).longValue());
} else {
throw new SeaTunnelException(
"Cannot convert timestamp to SCN. Make sure the specified timestamp is valid.");
}
});
} catch (SQLException e) {
LOG.error("Failed to convert timestamp to SCN", e);
throw new SeaTunnelException("Failed to convert timestamp to SCN", e);
}
}
public static List<TableId> listTables(
JdbcConnection jdbcConnection, String database, RelationalTableFilters tableFilters)
throws SQLException {
final List<TableId> capturedTableIds = new ArrayList<>();
Set<TableId> tableIdSet = new HashSet<>();
String queryTablesSql =
"SELECT OWNER ,TABLE_NAME,TABLESPACE_NAME FROM ALL_TABLES \n"
+ "WHERE PARTITIONED = 'YES' OR (TABLESPACE_NAME IS NOT NULL AND TABLESPACE_NAME NOT IN ('SYSAUX'))";View on GitHub (pinned to cf67b549a7)