{"record":{"id":"055f1928b2791b50","repo":"apache/iceberg","slug":"cannot-find-a-snapshot-after-scancontext-startsn","errorCode":null,"errorMessage":"Cannot find a snapshot after: {scanContext.startSnapshotTimestamp()}","messagePattern":"Cannot find a snapshot after: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"flink/v2.1/flink/src/main/java/org/apache/iceberg/flink/source/enumerator/ContinuousSplitPlannerImpl.java","lineNumber":244,"sourceCode":"      case INCREMENTAL_FROM_LATEST_SNAPSHOT_EXCLUSIVE:\n        return Optional.ofNullable(table.currentSnapshot());\n      case INCREMENTAL_FROM_EARLIEST_SNAPSHOT:\n        return Optional.ofNullable(SnapshotUtil.oldestAncestor(table));\n      case INCREMENTAL_FROM_SNAPSHOT_ID:\n        Snapshot matchedSnapshotById = table.snapshot(scanContext.startSnapshotId());\n        Preconditions.checkArgument(\n            matchedSnapshotById != null,\n            \"Start snapshot id not found in history: \" + scanContext.startSnapshotId());\n        return Optional.of(matchedSnapshotById);\n      case INCREMENTAL_FROM_SNAPSHOT_TIMESTAMP:\n        Snapshot matchedSnapshotByTimestamp =\n            SnapshotUtil.oldestAncestorAfter(table, scanContext.startSnapshotTimestamp());\n        Preconditions.checkArgument(\n            matchedSnapshotByTimestamp != null,\n            \"Cannot find a snapshot after: \" + scanContext.startSnapshotTimestamp());\n        return Optional.of(matchedSnapshotByTimestamp);\n      default:\n        throw new IllegalArgumentException(\n            \"Unknown starting strategy: \" + scanContext.streamingStartingStrategy());\n    }\n  }\n}\n","sourceCodeStart":226,"sourceCodeEnd":249,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/flink/v2.1/flink/src/main/java/org/apache/iceberg/flink/source/enumerator/ContinuousSplitPlannerImpl.java#L226-L249","documentation":"ContinuousSplitPlannerImpl.startSnapshot uses SnapshotUtil.oldestAncestorAfter to find the first snapshot at or after startSnapshotTimestamp for the TABLE_SCAN_THEN_INCREMENT/INCREMENTAL_FROM_TIMESTAMP strategy; Preconditions.checkArgument fails when no snapshot matches, meaning no snapshot exists after the given timestamp.","triggerScenarios":"Starting a streaming/incremental scan with start-snapshot-timestamp set to a time after the table's latest snapshot (or before which all snapshots were expired), so no ancestor snapshot matches.","commonSituations":"Timestamp computed from another table or an older run; table is brand new or all snapshots have been expired by retention rules; timezone/unit mistakes (seconds vs milliseconds) pushing the timestamp past the last snapshot.","solutions":["Check table.currentSnapshot().timestampMillis() and pick a start timestamp earlier than the oldest retained snapshot.","Remove the start-snapshot-timestamp option to start from the current snapshot instead.","Verify the timestamp is in milliseconds since epoch and not skewed by timezone or unit conversion.","Reduce snapshot expiration aggressiveness so retained history covers the requested timestamp."],"exampleFix":"// before\noptions.put(\"start-snapshot-timestamp\", String.valueOf(System.currentTimeMillis() + drift));\n// after\nSnapshot s = table.currentSnapshot();\nif (s != null && s.timestampMillis() > ts) {\n  ts = s.timestampMillis(); // clamp to a known snapshot time\n}\noptions.put(\"start-snapshot-timestamp\", String.valueOf(ts));","handlingStrategy":"validation","validationCode":"long ts = ...; // desired start timestamp in millis\nTable table = tableLoader.loadTable();\nlong oldest = SnapshotUtil.oldestAncestor(table) != null\n    ? SnapshotUtil.oldestAncestor(table).timestampMillis() : Long.MAX_VALUE;\nif (ts < oldest || ts > Optional.ofNullable(table.currentSnapshot())\n        .map(Snapshot::timestampMillis).orElse(Long.MAX_VALUE)) {\n  ts = oldest; // clamp to a retained snapshot\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Clamp start timestamps to the range of retained snapshots before configuring the source.","Use StartupOptions.snapshot() with a known snapshot ID instead of a raw timestamp.","Reconcile timestamp units (always epoch millis) and timezone sources.","Coordinate snapshot expiration with streaming readers."],"tags":["flink","snapshot","timestamp","argument-validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}