{"record":{"id":"6db39bdc38a373a5","repo":"apache/iceberg","slug":"failed-to-create-tablemaintenance","errorCode":null,"errorMessage":"Failed to create tableMaintenance ","messagePattern":"Failed to create tableMaintenance ","errorType":"exception","errorClass":"UncheckedIOException","httpStatus":null,"severity":"error","filePath":"flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/sink/IcebergSink.java","lineNumber":305,"sourceCode":"      } else {\n        builder = TableMaintenance.forChangeStream(tableChangeStream, tableLoader);\n      }\n\n      builder\n          .uidSuffix(tableMaintenanceUid)\n          .add(maintenanceTasks)\n          .rateLimit(Duration.ofSeconds(flinkMaintenanceConfig.rateLimit()))\n          .lockCheckDelay(Duration.ofSeconds(flinkMaintenanceConfig.lockCheckDelay()))\n          .parallelism(flinkMaintenanceConfig.parallelism());\n\n      String slotSharingGroup = flinkMaintenanceConfig.slotSharingGroup();\n      if (slotSharingGroup != null) {\n        builder.slotSharingGroup(slotSharingGroup);\n      }\n\n      builder.append();\n    } catch (IOException e) {\n      throw new UncheckedIOException(\"Failed to create tableMaintenance \", e);\n    }\n  }\n\n  @Override\n  public DataStream<RowData> addPreWriteTopology(DataStream<RowData> inputDataStream) {\n    return distributeDataStream(inputDataStream);\n  }\n\n  @Override\n  public DataStream<CommittableMessage<IcebergCommittable>> addPreCommitTopology(\n      DataStream<CommittableMessage<WriteResult>> writeResults) {\n    TypeInformation<CommittableMessage<IcebergCommittable>> typeInformation =\n        CommittableMessageTypeInfo.of(this::getCommittableSerializer);\n\n    String suffix = defaultSuffix(uidSuffix, table.name());\n    String preCommitAggregatorUid = String.format(\"Sink pre-commit aggregator: %s\", suffix);\n\n    // global forces all output records send to subtask 0 of the downstream committer operator.","sourceCodeStart":287,"sourceCodeEnd":323,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/sink/IcebergSink.java#L287-L323","documentation":"IcebergSink.addPostCommitTopology builds the TableMaintenance operator from the maintenance config; if constructing the lock config or the maintenance builder throws an IOException it is wrapped in UncheckedIOException 'Failed to create tableMaintenance'. The cause reveals whether lock-factory setup or IO during operator creation failed.","triggerScenarios":"Enabling table maintenance (maintenance config) where TableMaintenance.Builder.append() or LockFactoryBuilder.build/createLockConfig performs IO that fails — e.g. creating/reaching a distributed lock (JDBC, ZooKeeper) or reading lock-related configuration resources.","commonSituations":"Misconfigured table.maintenance.* lock properties (bad lock type/URL), lock store database/table unreachable, missing credentials for the lock backend, or a maintenance task builder doing IO that fails (catalog access during task setup).","solutions":["Read the chained IOException cause for the real failure (lock store connection, missing resource, etc.)","Verify maintenance lock config properties (lock type, lock store URI/credentials) — try running without lock config (no lockType) to isolate","Confirm the lock backend (e.g. JDBC database, ZooKeeper quorum) is reachable from the job manager","Validate each configured maintenance task (expire snapshots, orphan cleanup, rewrite data files) can run against the table with the job's FileIO credentials"],"exampleFix":"// before\nTableMaintenance.forChangeStream(changeStream, loader)\n    .add(RewriteDataFilesExecutor.fromConfig(table)) // throws IOException\n    .append();\n// after\n// ensure lock/task IO deps are configured & reachable first\nLockConfig lockConfig = flinkMaintenanceConfig.createLockConfig();\nLOG.info(\"maintenance lock type={}\", lockConfig.lockType());\n// fix lock store endpoint/credentials, then retry append()","handlingStrategy":"validation","validationCode":"// before enabling maintenance, verify lock config resolves and backend is reachable\nLockConfig lockConfig = flinkMaintenanceConfig.createLockConfig();\nif (StringUtils.isNotEmpty(lockConfig.lockType())) {\n  LockFactory f = LockFactoryBuilder.build(lockConfig, tableName); // throws early if misconfigured\n  LOG.info(\"maintenance lock: {} via {}\", lockConfig.lockType(), f);\n}","typeGuard":null,"tryCatchPattern":"try {\n  sink.addPostCommitTopology(committables);\n} catch (UncheckedIOException e) {\n  LOG.error(\"tableMaintenance creation failed: {}\", e.getCause(), e);\n  // disable maintenance tasks and resubmit to isolate the cause\n  throw e;\n}","preventionTips":["Validate table.maintenance.* lock properties (type, URI, credentials) before submission","Test the lock backend connectivity from the job manager host","Enable one maintenance task at a time to isolate IO failures","Keep the no-lock fallback path (empty lockType) as an isolation lever"],"tags":["flink","maintenance","io","iceberg"],"backgroundTag":"invalid-config-value","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}