{"record":{"id":"2e3caf3cc56dd1a3","repo":"apache/iceberg","slug":"cannot-manage-snapshots-in-a-s-table","errorCode":null,"errorMessage":"Cannot manage snapshots in a %s table","messagePattern":"Cannot manage snapshots in a (.+?) table","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/BaseReadOnlyTable.java","lineNumber":117,"sourceCode":"    throw new UnsupportedOperationException(\n        \"Cannot update statistics of a \" + descriptor + \" table\");\n  }\n\n  @Override\n  public UpdatePartitionStatistics updatePartitionStatistics() {\n    throw new UnsupportedOperationException(\n        \"Cannot update partition statistics of a \" + descriptor + \" table\");\n  }\n\n  @Override\n  public ExpireSnapshots expireSnapshots() {\n    throw new UnsupportedOperationException(\n        \"Cannot expire snapshots from a \" + descriptor + \" table\");\n  }\n\n  @Override\n  public ManageSnapshots manageSnapshots() {\n    throw new UnsupportedOperationException(\n        \"Cannot manage snapshots in a \" + descriptor + \" table\");\n  }\n\n  @Override\n  public Transaction newTransaction() {\n    throw new UnsupportedOperationException(\n        \"Cannot create transactions for a \" + descriptor + \" table\");\n  }\n}\n","sourceCodeStart":99,"sourceCodeEnd":127,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/BaseReadOnlyTable.java#L99-L127","documentation":"ManageSnapshots performs metadata mutations (rollback, cherry-pick, branch/tag management) which require a writable table. BaseReadOnlyTable.manageSnapshots() always throws UnsupportedOperationException.","triggerScenarios":"Calling table.manageSnapshots() on a read-only descriptor such as a snapshot wrapper obtained from a table's snapshot APIs.","commonSituations":"Rollback tooling that grabbed a snapshot handle and tried to roll the table back to it directly.","solutions":["Load the real table via catalog.loadTable() and call manageSnapshots() on it.","Use rollback on the writable table: table.manageSnapshots().rollbackTo(snapshotId).commit().","Ensure time-travel reads use the read-only handle only for scanning."],"exampleFix":"// before\nreadOnlyTable.manageSnapshots().rollbackTo(snapshotId).commit();\n// after\nTable table = catalog.loadTable(tableIdentifier);\ntable.manageSnapshots().rollbackTo(snapshotId).commit();","handlingStrategy":"validation","validationCode":"if (!(table instanceof BaseReadOnlyTable)) {\n  table.manageSnapshots().rollbackTo(snapshotId).commit();\n}","typeGuard":"boolean supportsSnapshotManagement(Table t) { return !(t instanceof BaseReadOnlyTable); }","tryCatchPattern":"try { table.manageSnapshots().rollbackTo(id).commit(); } catch (UnsupportedOperationException e) { /* reload from catalog */ }","preventionTips":["Roll back via the live table, not snapshot wrappers","Validate handle writability in rollback tooling"],"tags":["unsupported-operation","read-only-table","snapshot-management"],"backgroundTag":"unsupported-operation","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}