{"record":{"id":"807dc1d179308b3b","repo":"apache/iceberg","slug":"failed-to-update-table-s-from-catalog-s","errorCode":null,"errorMessage":"Failed to update table %s from catalog %s","messagePattern":"Failed to update table (.+?) from catalog (.+?)","errorType":"exception","errorClass":"CommitFailedException","httpStatus":null,"severity":"warning","filePath":"core/src/main/java/org/apache/iceberg/jdbc/JdbcTableOperations.java","lineNumber":160,"sourceCode":"      throw new UncheckedInterruptedException(e, \"Interrupted during commit\");\n    }\n  }\n\n  private void updateTable(String newMetadataLocation, String oldMetadataLocation)\n      throws SQLException, InterruptedException {\n    int updatedRecords =\n        JdbcUtil.updateTable(\n            schemaVersion,\n            connections,\n            catalogName,\n            tableIdentifier,\n            newMetadataLocation,\n            oldMetadataLocation);\n\n    if (updatedRecords == 1) {\n      LOG.debug(\"Successfully committed to existing table: {}\", tableIdentifier);\n    } else {\n      throw new CommitFailedException(\n          \"Failed to update table %s from catalog %s\", tableIdentifier, catalogName);\n    }\n  }\n\n  private void createTable(String newMetadataLocation) throws SQLException, InterruptedException {\n    Namespace namespace = tableIdentifier.namespace();\n    if (PropertyUtil.propertyAsBoolean(catalogProperties, JdbcUtil.STRICT_MODE_PROPERTY, false)\n        && !JdbcUtil.namespaceExists(catalogName, connections, namespace)) {\n      throw new NoSuchNamespaceException(\n          \"Cannot create table %s in catalog %s. Namespace %s does not exist\",\n          tableIdentifier, catalogName, namespace);\n    }\n\n    if (schemaVersion == JdbcUtil.SchemaVersion.V1\n        && JdbcUtil.viewExists(catalogName, connections, tableIdentifier)) {\n      throw new AlreadyExistsException(\"View with same name already exists: %s\", tableIdentifier);\n    }\n","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/jdbc/JdbcTableOperations.java#L142-L178","documentation":"updateTable performs an atomic UPDATE of the metadata location guarded by the old location (WHERE metadata_location = oldMetadataLocation). If exactly one row is not updated (updatedRecords != 1) the concurrent state no longer matches the base, so a CommitFailedException is thrown. This is Iceberg's normal optimistic-concurrency retry signal: the caller (BaseTable/CommitState) is expected to refresh and retry the commit.","triggerScenarios":"Two writers committed between this job's refresh and its commit, so the row's metadata_location no longer equals the base location; the table was dropped and recreated; the UPDATE matched 0 rows due to wrong tableIdentifier/catalogName casing on case-sensitive DBs.","commonSituations":"Multiple Spark/Flink jobs writing to the same table concurrently; a compaction job racing with streaming ingest; manual metadata file edits; case-sensitive Postgres vs case-insensitive MySQL identifier mismatches.","solutions":["Retry the commit with a refreshed table: load the table again so base reflects the latest metadata, then reapply changes (Iceberg's commit retry loop does this automatically)","Reduce write contention or partition writes so concurrent commits to one table are rare","Check identifier casing against the DB's case-sensitivity rules if retries never succeed","If the table was recreated, re-point the job at the new table instead of committing stale state"],"exampleFix":"// before\nTable table = catalog.loadTable(ident);\ntable.refresh();\ntable.newAppend().appendFile(f).commit(); // single shot, fails on race\n// after\nTasks.foreach(table)\n    .retry(10)\n    .onlyRetryOn(CommitFailedException.class)\n    .run(t -> t.newAppend().appendFile(f).commit());","handlingStrategy":"retry","validationCode":"table.refresh(); // ensure base metadata location matches catalog before commit","typeGuard":null,"tryCatchPattern":"Tasks.foreach(table).retry(10).onlyRetryOn(CommitFailedException.class).run(t -> t.transaction().commitTransaction());","preventionTips":["Always commit through Iceberg's retrying commit path; never wrap in a single-shot call","Refresh tables before commits in long-running jobs","Minimize concurrent writers per table or partition workloads","Keep identifiers' casing consistent with the DB collation"],"tags":["jdbc","optimistic-concurrency","commit-retry","catalog-commit"],"backgroundTag":"invalid-state-transition","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"}