{"record":{"id":"1e0571de27b4c918","repo":"apache/seatunnel","slug":"bigtablesourcesplitenumerator-already-closed-cann","errorCode":null,"errorMessage":"BigtableSourceSplitEnumerator already closed; cannot create client","messagePattern":"BigtableSourceSplitEnumerator already closed; cannot create client","errorType":"exception","errorClass":"EnumeratorClosedException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-google-bigtable/src/main/java/org/apache/seatunnel/connectors/seatunnel/bigtable/source/BigtableSourceSplitEnumerator.java","lineNumber":423,"sourceCode":"\n    /**\n     * Returns the shared client, creating it outside {@link #stateLock} when needed.\n     *\n     * <p>Construction is unlocked so a slow gRPC channel / credential load does not stall\n     * checkpoint snapshotting. Before publishing the new instance, this method re-checks under the\n     * lock: if another thread already published a client, or if {@link #close()} has already set\n     * {@code closed}, the just-built instance is closed immediately and never leaked.\n     *\n     * @throws EnumeratorClosedException if the enumerator is already closed (or closes during\n     *     construction), so callers can distinguish shutdown from a real sampleRowKeys failure\n     */\n    private BigtableClient getBigtableClient() {\n        synchronized (stateLock) {\n            if (bigtableClient != null) {\n                return bigtableClient;\n            }\n            if (closed) {\n                throw new EnumeratorClosedException(\n                        \"BigtableSourceSplitEnumerator already closed; cannot create client\");\n            }\n        }\n        BigtableClient created = BigtableClient.createInstance(parameters);\n        synchronized (stateLock) {\n            if (closed) {\n                created.close();\n                throw new EnumeratorClosedException(\n                        \"BigtableSourceSplitEnumerator closed during client creation\");\n            }\n            if (bigtableClient == null) {\n                bigtableClient = created;\n                return created;\n            }\n            created.close();\n            return bigtableClient;\n        }\n    }","sourceCodeStart":405,"sourceCodeEnd":441,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-google-bigtable/src/main/java/org/apache/seatunnel/connectors/seatunnel/bigtable/source/BigtableSourceSplitEnumerator.java#L405-L441","documentation":"BigtableSourceSplitEnumerator.getBigtableClient() checks the closed flag under stateLock before creating a BigtableClient and throws EnumeratorClosedException if the enumerator has already been closed. This prevents constructing a new gRPC client for a stopped split enumeration (e.g. after job cancel/failover), which would leak resources.","triggerScenarios":"buildSplits() calls getBigtableClient() after the enumerator's close() ran — typically a race between split enumeration and job cancellation/failover, or a late openSplitEnumerator callback firing on a shut-down reader context.","commonSituations":"Cancelling a job while the enumerator is still enumerating splits; failover where a restored coordinator races the old instance's cleanup; slow first split enumeration on a large table hit by an early shutdown.","solutions":["Retry/re-submit the job; this is usually a benign race — the new enumerator will recreate the client.","If it recurs, check coordinator/worker logs for premature close() (e.g. checkpoint timeout or heartbeat loss) and increase relevant timeouts.","Reduce split enumeration time (narrow the table/key range) so enumeration finishes before shutdown can race it."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  enumerator.open();\n} catch (EnumeratorClosedException e) {\n  // enumerator was shut down concurrently; coordinator retry will recreate it\n  log.warn(\"Enumerator closed during split build, awaiting restart: {}\", e.getMessage());\n}","preventionTips":["Avoid cancelling jobs during initial split enumeration when possible.","Ensure coordinator heartbeats/timeouts comfortably exceed enumeration duration.","Narrow table scan ranges so enumeration completes quickly."],"tags":["bigtable","source","lifecycle","race-condition"],"backgroundTag":"invalid-state-transition","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}