apache/iceberg · critical · IllegalStateException
Cannot load current offset at snapshot %d, the snapshot was
Error message
Cannot load current offset at snapshot %d, the snapshot was expired or removed
What it means
Spark streaming reads track progress via StreamingOffsets that reference a snapshot ID. When resuming or planning the next micro-batch, the stored snapshot must still exist; if table snapshot expiration removed it, validateCurrentSnapshotExists throws IllegalStateException so the stream fails instead of silently skipping data.
Source
Thrown at spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/source/SyncSparkMicroBatchPlanner.java:242
startPosOfSnapOffset = -1;
// if anyhow we are moving to next snapshot we should only scan addedFiles
scanAllFiles = false;
}
}
StreamingOffset latestStreamingOffset =
new StreamingOffset(curSnapshot.snapshotId(), curPos, scanAllFiles);
// if no new data arrived, then return null.
return latestStreamingOffset.equals(startingOffset) ? null : latestStreamingOffset;
}
@Override
public void stop() {}
private void validateCurrentSnapshotExists(Snapshot snapshot, StreamingOffset currentOffset) {
if (snapshot == null) {
throw new IllegalStateException(
String.format(
Locale.ROOT,
"Cannot load current offset at snapshot %d, the snapshot was expired or removed",
currentOffset.snapshotId()));
}
}
}
View on GitHub (pinned to 86d9c8fc54)
Solutions
- Restore the stream from a checkpoint taken before the referenced snapshot was expired, or start a new stream with a fresh checkpoint (accepting a new starting snapshot)
- Pause snapshot expiration (increase retention / stop expireSnapshots) while streams are active; keep min-snapshot-retention above max stream pause time
- If data loss from restarting is unacceptable, recover the expired snapshot from backups/metadata and reload the table state
- Set expireSnapshots' older-than based on the oldest streaming checkpoint's snapshot id before expiring
Example fix
// before
spark.sql("CALL catalog.system.expire_snapshots('db.t', TIMESTAMP '2026-08-01 00:00:00')");
// after
// keep at least 7 days so active streams' offsets remain valid
spark.sql("CALL catalog.system.expire_snapshots('db.t', TIMESTAMP '2026-09-04 00:00:00', map('streaming-max-snapshot-age-ms','604800000'))"); Defensive patterns
Strategy: try-catch
Validate before calling
// before resuming a stream, verify the checkpoint's snapshot still exists
Snapshot s = table.snapshot(currentOffset.snapshotId());
if (s == null) {
throw new IllegalStateException("Checkpoint snapshot " + currentOffset.snapshotId()
+ " expired; restart stream from a valid snapshot");
} Try / catch
try {
streamQuery.processAllAvailable();
} catch (IllegalStateException e) {
if (e.getMessage().contains("the snapshot was expired or removed")) {
// restart stream with fresh checkpoint or restore the snapshot
} else { throw e; }
} Prevention
- Keep expireSnapshots retention longer than any stream pause
- Check oldest streaming checkpoint age before expiring snapshots
- Coordinate table maintenance with owners of streaming jobs
- Alert on streams that remain stopped beyond snapshot retention
When it happens
Trigger: A running Spark structured streaming query resumes from a checkpoint whose offset references snapshot N, but snapshot N was expired by expireSnapshots, retention policies, or a concurrent table maintenance job.
Common situations: expireSnapshots run (manually or via a scheduled cleanup) with a retention shorter than the stream's checkpoint age; shared table where another team expires snapshots; long-paused stream resumed after snapshot cleanup.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Failed to parse StreamingOffset from JSON string %s
- Failed writing offset to: %s
- Failed reading offset from: %s
- Failed to parse StreamingOffset from JSON string %s
- Cannot load current offset at snapshot %d, the snapshot was
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/d830d1bfb4a882cf.
Report an issue: GitHub.