apache/seatunnel · error · IllegalStateException

The split fetcher manager has closed.

Error message

The split fetcher manager has closed.

What it means

SplitFetcherManager.createSplitFetcher() is guarded against use after the manager has been closed. When closed==true it throws this IllegalStateException instead of creating a fetcher whose executor no longer exists, keeping shutdown state consistent.

Source

Thrown at seatunnel-connectors-v2/connector-common/src/main/java/org/apache/seatunnel/connectors/seatunnel/common/source/reader/fetcher/SplitFetcherManager.java:98

                        // Add the exception to the exception list.
                        uncaughtFetcherException.get().addSuppressed(throwable);
                    }
                };
        String taskThreadName = Thread.currentThread().getName();
        this.executors =
                Executors.newCachedThreadPool(
                        r -> new Thread(r, "Source Data Fetcher for " + taskThreadName));
    }

    public abstract void addSplits(Collection<SplitT> splitsToAdd);

    protected void startFetcher(SplitFetcher<E, SplitT> fetcher) {
        executors.submit(fetcher);
    }

    protected synchronized SplitFetcher<E, SplitT> createSplitFetcher() {
        if (closed) {
            throw new IllegalStateException("The split fetcher manager has closed.");
        }
        // Create SplitReader.
        SplitReader<E, SplitT> splitReader = splitReaderFactory.get();
        int fetcherId = fetcherIdGenerator.getAndIncrement();
        SplitFetcher<E, SplitT> splitFetcher =
                new SplitFetcher<>(
                        fetcherId,
                        elementsQueue,
                        splitReader,
                        errorHandler,
                        () -> {
                            fetchers.remove(fetcherId);
                        },
                        this.splitFinishedHook);
        fetchers.put(fetcherId, splitFetcher);
        return splitFetcher;
    }

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Check job lifecycle: ensure addSplits isn't called after close — this is usually a race, so check shutdown ordering logs
  2. Retry-safe pattern: catch IllegalStateException and drop splits if the reader is intentionally closed
  3. Fix the race by synchronizing split assignment against reader shutdown in the enumerator/reader glue
  4. Upgrade SeaTunnel if a known race between close() and addSplits() is the trigger

Example fix

// before
splitFetcherManager.addSplits(splits); // may throw after close
// after
if (!splitFetcherManager.isClosed()) { // guard via manager state where exposed
    splitFetcherManager.addSplits(splits);
}
Defensive patterns

Strategy: validation

Validate before calling

// guard against adding splits after close
if (splitFetcherManager.isClosed()) { // expose/query closed state if available
    LOG.warn("split fetcher manager closed; dropping {} splits", splits.size());
    return;
}
splitFetcherManager.addSplits(splits);

Type guard

boolean canAcceptSplits(SplitFetcherManager<?, ?> m) {
    try {
        java.lang.reflect.Field f = m.getClass().getDeclaredField("closed");
        f.setAccessible(true);
        return !f.getBoolean(m);
    } catch (ReflectiveOperationException e) {
        return false;
    }
}

Try / catch

try {
    splitFetcherManager.addSplits(splits);
} catch (IllegalStateException e) {
    if (e.getMessage().contains("split fetcher manager has closed")) {
        LOG.warn("manager closed during split assignment; ignoring", e);
        return;
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling addSplits (or any path that lazily creates a fetcher) after SplitFetcherManager.close() has run — e.g. splits arriving while the reader is being closed, or a race between SplitEnumerator assigning splits and source reader closure.

Common situations: Job cancel/fail concurrently with split assignment; checkpoint recovery ordering where a stale reader receives splits; user code closing the source reader then adding splits.

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/3780e1f5377df0f6. Report an issue: GitHub.