{"record":{"id":"4622527a207d1263","repo":"apache/iceberg","slug":"cannot-modify-a-static-table","errorCode":null,"errorMessage":"Cannot modify a static table","messagePattern":"Cannot modify a static table","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/StaticTableOperations.java","lineNumber":80,"sourceCode":"      staticMetadata = TableMetadataParser.read(io, metadataFileLocation);\n    }\n    return staticMetadata;\n  }\n\n  /**\n   * StaticTableOperations works on the same version of TableMetadata, and it will never refer a\n   * different TableMetadata object than the one it was created with.\n   *\n   * @return always {@link #current()}.\n   */\n  @Override\n  public TableMetadata refresh() {\n    return current();\n  }\n\n  @Override\n  public void commit(TableMetadata base, TableMetadata metadata) {\n    throw new UnsupportedOperationException(\"Cannot modify a static table\");\n  }\n\n  @Override\n  public FileIO io() {\n    return this.io;\n  }\n\n  @Override\n  public String metadataFileLocation(String fileName) {\n    throw new UnsupportedOperationException(\"Cannot modify a static table\");\n  }\n\n  @Override\n  public LocationProvider locationProvider() {\n    return locationProvider;\n  }\n}\n","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/StaticTableOperations.java#L62-L98","documentation":"StaticTableOperations.commit throws UnsupportedOperationException because a static table is a read-only view over a fixed TableMetadata (typically used to read time-travel snapshots or Hadoop-provided metadata files without a catalog). Committing changes to a static table is intentionally impossible — mutations must go through a real catalog-backed Table.","triggerScenarios":"Calling any write/DDL operation on a static table — table.updateSchema().commit(), appendFiles(table).commit(), refreshAndCreateTransaction, updateLocation, etc. — where the Table was built from StaticTableOperations (e.g. via new StaticTableOperations(metadataFile, io) or time-travel/static readers).","commonSituations":"Loading a table with Table.load static helpers or time-travel snapshots and then attempting appends/schema updates; scripts that migrate from Hive tables loaded statically; assuming every Table handle is writable because the Table interface exposes write APIs.","solutions":["Load a catalog-backed table instead of a static one, then perform writes through it (catalog.loadTable(identifier) and use the returned Table for mutations).","If you need time travel plus writes, use table.timeMachine-style snapshot selection (Spark: VERSION AS OF) on the catalog table rather than a static table handle.","For metadata changes, operate on the source catalog: e.g. HiveCatalog/RESTCatalog loadTable -> update operations -> commit.","Restructure code to treat statically-loaded tables as read-only and route writes to a separate writable handle."],"exampleFix":"// before\nTable table = new BaseTable(\n    new StaticTableOperations(metadataFileLocation, fileIO), \"static\");\ntable.updateSchema().addColumn(\"new_col\", Types.StringType.get()).commit(); // throws\n\n// after\nCatalog catalog = ...; // e.g. HiveCatalog / RESTCatalog\nTable table = catalog.loadTable(TableIdentifier.of(\"db\", \"tbl\"));\ntable.updateSchema().addColumn(\"new_col\", Types.StringType.get()).commit();","handlingStrategy":"try-catch","validationCode":"// Java: detect static tables before writing\nif (((HasTableOperations) table).operations() instanceof StaticTableOperations) {\n  throw new IllegalStateException(\"Load via a Catalog to write this table\");\n}","typeGuard":"// Java\nboolean isWritable(Table table) {\n  return !(((HasTableOperations) table).operations() instanceof StaticTableOperations);\n}","tryCatchPattern":"// Java\ntry {\n  table.updateSchema().addColumn(\"c\", Types.StringType.get()).commit();\n} catch (UnsupportedOperationException e) {\n  if (e.getMessage().contains(\"static table\")) {\n    Table live = catalog.loadTable(tableIdentifier);\n    live.updateSchema().addColumn(\"c\", Types.StringType.get()).commit();\n  } else { throw e; }\n}","preventionTips":["Only use static tables for read-only inspection or time-travel reads.","Always load tables from a Catalog when the workflow includes writes or DDL.","Document/review code paths that construct BaseTable with StaticTableOperations."],"tags":["read-only","static-table","commit","iceberg"],"backgroundTag":"unsupported-operation","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"}