{"record":{"id":"76491e39793c15e3","repo":"apache/iceberg","slug":"not-implemented-docommit","errorCode":null,"errorMessage":"Not implemented: doCommit","messagePattern":"Not implemented: doCommit","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/BaseMetastoreTableOperations.java","lineNumber":138,"sourceCode":"    // if the metadata is not changed, return early\n    if (base == metadata) {\n      LOG.info(\"Nothing to commit.\");\n      return;\n    }\n\n    long start = System.currentTimeMillis();\n    doCommit(base, metadata);\n    CatalogUtil.deleteRemovedMetadataFiles(io(), base, metadata);\n    requestRefresh();\n\n    LOG.info(\n        \"Successfully committed to table {} in {} ms\",\n        tableName(),\n        System.currentTimeMillis() - start);\n  }\n\n  protected void doCommit(TableMetadata base, TableMetadata metadata) {\n    throw new UnsupportedOperationException(\"Not implemented: doCommit\");\n  }\n\n  protected void requestRefresh() {\n    this.shouldRefresh = true;\n  }\n\n  protected void disableRefresh() {\n    this.shouldRefresh = false;\n  }\n\n  protected String writeNewMetadataIfRequired(boolean newTable, TableMetadata metadata) {\n    return newTable && metadata.metadataFileLocation() != null\n        ? metadata.metadataFileLocation()\n        : writeNewMetadata(metadata, currentVersion() + 1);\n  }\n\n  protected String writeNewMetadata(TableMetadata metadata, int newVersion) {\n    String newTableMetadataFilePath = newTableMetadataFilePath(metadata, newVersion);","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/BaseMetastoreTableOperations.java#L120-L156","documentation":"BaseMetastoreTableOperations.doCommit(base, metadata) is the abstract hook subclasses implement to write metadata to their metastore. The base class throws UnsupportedOperationException, so committing through an operations instance that lacks a doCommit override always fails. Like doRefresh, this flags an incomplete custom catalog implementation.","triggerScenarios":"Calling commit(base, metadata) (including the early no-op guard passing) on a subclass that does not override doCommit; requestRefresh/commit flows in a half-implemented custom catalog.","commonSituations":"Custom Hive/Nessie/Glue-style catalogs missing the doCommit override; test stubs of BaseMetastoreTableOperations used in production paths; incomplete migration to a newer base-class API.","solutions":["Override doCommit(base, metadata) in the subclass to persist the new metadata file and update the metastore pointer","Persist a new metadata file via writeNewMetadata(metadata, overwrite) then update the metastore location atomically","Point the catalog at a complete TableOperations implementation"],"exampleFix":"// before\nclass MyTableOperations extends BaseMetastoreTableOperations { }\n// after\nclass MyTableOperations extends BaseMetastoreTableOperations {\n  @Override\n  protected void doCommit(TableMetadata base, TableMetadata metadata) {\n    String newLocation = writeNewMetadata(metadata, version >= 0 /* overwrite */);\n    updateMetastoreTable(metadataLocation(), newLocation);\n  }\n}","handlingStrategy":"type-guard","validationCode":"if (ops.getClass().getMethod(\"doCommit\", TableMetadata.class, TableMetadata.class).getDeclaringClass() == BaseMetastoreTableOperations.class) { throw new IllegalStateException(\"Custom ops must override doCommit\"); }","typeGuard":"static boolean supportsCommit(TableOperations ops) { return !(ops instanceof BaseMetastoreTableOperations) || !ops.getClass().getName().equals(BaseMetastoreTableOperations.class.getName()); }","tryCatchPattern":"try { ops.commit(base, metadata); }\ncatch (UnsupportedOperationException e) { /* doCommit not implemented; complete the custom implementation */ }","preventionTips":["Always override doCommit when extending BaseMetastoreTableOperations","Test commit paths against a real metastore backend","Use writeNewMetadata + atomic metastore update in the override"],"tags":["unsupported-operation","custom-catalog","abstract-method"],"backgroundTag":"method-not-implemented","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"}