apache/seatunnel · error · EnumeratorClosedException

BigtableSourceSplitEnumerator already closed; cannot create

Error message

BigtableSourceSplitEnumerator already closed; cannot create client

What it means

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.

Source

Thrown at seatunnel-connectors-v2/connector-google-bigtable/src/main/java/org/apache/seatunnel/connectors/seatunnel/bigtable/source/BigtableSourceSplitEnumerator.java:423

    /**
     * Returns the shared client, creating it outside {@link #stateLock} when needed.
     *
     * <p>Construction is unlocked so a slow gRPC channel / credential load does not stall
     * checkpoint snapshotting. Before publishing the new instance, this method re-checks under the
     * lock: if another thread already published a client, or if {@link #close()} has already set
     * {@code closed}, the just-built instance is closed immediately and never leaked.
     *
     * @throws EnumeratorClosedException if the enumerator is already closed (or closes during
     *     construction), so callers can distinguish shutdown from a real sampleRowKeys failure
     */
    private BigtableClient getBigtableClient() {
        synchronized (stateLock) {
            if (bigtableClient != null) {
                return bigtableClient;
            }
            if (closed) {
                throw new EnumeratorClosedException(
                        "BigtableSourceSplitEnumerator already closed; cannot create client");
            }
        }
        BigtableClient created = BigtableClient.createInstance(parameters);
        synchronized (stateLock) {
            if (closed) {
                created.close();
                throw new EnumeratorClosedException(
                        "BigtableSourceSplitEnumerator closed during client creation");
            }
            if (bigtableClient == null) {
                bigtableClient = created;
                return created;
            }
            created.close();
            return bigtableClient;
        }
    }

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Retry/re-submit the job; this is usually a benign race — the new enumerator will recreate the client.
  2. If it recurs, check coordinator/worker logs for premature close() (e.g. checkpoint timeout or heartbeat loss) and increase relevant timeouts.
  3. Reduce split enumeration time (narrow the table/key range) so enumeration finishes before shutdown can race it.
Defensive patterns

Strategy: retry

Try / catch

try {
  enumerator.open();
} catch (EnumeratorClosedException e) {
  // enumerator was shut down concurrently; coordinator retry will recreate it
  log.warn("Enumerator closed during split build, awaiting restart: {}", e.getMessage());
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/1e0571de27b4c918. Report an issue: GitHub.