{"record":{"id":"2dbf389ce3d96dc4","repo":"apache/iceberg","slug":"deleted-manifest-s-could-not-be-found-in-the-late","errorCode":null,"errorMessage":"Deleted manifest %s could not be found in the latest snapshot %d","messagePattern":"Deleted manifest (.+?) could not be found in the latest snapshot (.+?)","errorType":"validation","errorClass":"ValidationException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/BaseRewriteManifests.java","lineNumber":294,"sourceCode":"  }\n\n  private boolean containsDeletes(ManifestFile manifest) {\n    return manifest.content() == ManifestContent.DELETES;\n  }\n\n  private boolean matchesPredicate(ManifestFile manifest) {\n    return predicate == null || predicate.test(manifest);\n  }\n\n  private void validateDeletedManifests(\n      Set<ManifestFile> currentManifests, long currentSnapshotID) {\n    // directly deleted manifests must be still present in the current snapshot\n    deletedManifests.stream()\n        .filter(manifest -> !currentManifests.contains(manifest))\n        .findAny()\n        .ifPresent(\n            manifest -> {\n              throw new ValidationException(\n                  \"Deleted manifest %s could not be found in the latest snapshot %d\",\n                  manifest.path(), currentSnapshotID);\n            });\n  }\n\n  private void validateFilesCounts() {\n    Iterable<ManifestFile> createdManifests =\n        Iterables.concat(newManifests, addedManifests, rewrittenAddedManifests);\n    int createdManifestsFilesCount = activeFilesCount(createdManifests);\n\n    Iterable<ManifestFile> replacedManifests =\n        Iterables.concat(rewrittenManifests, deletedManifests);\n    int replacedManifestsFilesCount = activeFilesCount(replacedManifests);\n\n    if (createdManifestsFilesCount != replacedManifestsFilesCount) {\n      throw new ValidationException(\n          \"Replaced and created manifests must have the same number of active files: %d (new), %d (old)\",\n          createdManifestsFilesCount, replacedManifestsFilesCount);","sourceCodeStart":276,"sourceCodeEnd":312,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/BaseRewriteManifests.java#L276-L312","documentation":"RewriteManifests may delete manifests directly (when all entries are rewritten) and expects those deleted manifests to still be present in the snapshot that apply() is based on. validateDeletedManifests throws this ValidationException if any manifest slated for deletion is no longer in the latest snapshot, meaning the table changed concurrently and the rewrite is stale.","triggerScenarios":"Calling apply()/commit() on a RewritePartitions-style rewrite whose base snapshot is no longer current: another writer expired snapshots or committed new manifests between when the rewrite was planned and committed.","commonSituations":"A long-running rewriteManifests job racing with concurrent ingestion (new snapshots appended); snapshots expired by a maintenance job while the rewrite was in flight.","solutions":["Refresh the table and re-run rewriteManifests() from the latest snapshot.","Wrap the commit in a retry that rebuilds the operation after CommitFailedException/ValidationException.","Pause concurrent snapshot expiration during manifest rewrites, or sequence maintenance jobs.","Keep rewrite jobs short-lived to narrow the race window."],"exampleFix":"// before\ntable.rewriteManifests().clusterBy(f -> f.partition()).commit(); // may throw once\n// after\nTasks.foreach(new Object[] {null})\n    .retry(3)\n    .run(ignored ->\n        table.refresh().rewriteManifests().clusterBy(f -> f.partition()).commit());","handlingStrategy":"retry","validationCode":"// before commit, verify planned manifests still exist in the latest snapshot\nSnapshot current = table.currentSnapshot();\nSet<String> present = current.allManifests(table.io()).stream()\n    .map(m -> m.path().toString()).collect(Collectors.toSet());\nboolean stale = plannedDeleted.stream().anyMatch(m -> !present.contains(m.path().toString()));\nif (stale) { table.refresh(); /* rebuild the rewrite */ }","typeGuard":null,"tryCatchPattern":"try {\n  table.rewriteManifests().clusterBy(f -> f.partition()).commit();\n} catch (ValidationException e) {\n  if (e.getMessage().contains(\"could not be found in the latest snapshot\")) {\n    table.refresh(); // rebuild rewrite from latest snapshot and retry\n  } else throw e;\n}","preventionTips":["Always refresh the table before building a manifest rewrite","Retry rewrites that fail because the table moved underneath them","Avoid running snapshot expiration concurrently with rewriteManifests","Keep rewrite jobs short to minimize the race window with concurrent commits"],"tags":["validation","concurrent-modification","manifest-rewrite","snapshot"],"backgroundTag":"resource-not-found","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"}