apache/flink · error · IllegalArgumentException

Cannot create empty classifier chain.

Error message

Cannot create empty classifier chain.

What it means

Thrown as an IllegalArgumentException by FatalExceptionClassifier.createChain when called with zero arguments. createChain links FatalExceptionClassifier instances into a chain for cascaded exception classification. An empty chain has no meaning and is rejected immediately as a programming error.

Source

Thrown at flink-connectors/flink-connector-base/src/main/java/org/apache/flink/connector/base/sink/throwable/FatalExceptionClassifier.java:67

        if (chainedClassifier != null) {
            return chainedClassifier.isFatal(err, throwableConsumer);
        } else {
            return true;
        }
    }

    public static FatalExceptionClassifier withRootCauseOfType(
            Class<? extends Throwable> type, Function<Throwable, Exception> mapper) {
        return new FatalExceptionClassifier(
                err -> ExceptionUtils.findThrowable(err, type).isPresent(), mapper);
    }

    public static FatalExceptionClassifier createChain(FatalExceptionClassifier... classifiers) {
        Set<FatalExceptionClassifier> importedClassifiers = new HashSet<>();

        if (classifiers.length == 0) {
            throw new IllegalArgumentException("Cannot create empty classifier chain.");
        }

        FatalExceptionClassifier tailClassifier = classifiers[0];
        importedClassifiers.add(tailClassifier);

        for (int i = 1; i < classifiers.length; ++i) {
            if (importedClassifiers.contains(classifiers[i])) {
                throw new IllegalArgumentException(
                        "Wrong classifier chain; Circular chain of classifiers detected.");
            }

            tailClassifier.chainedClassifier = classifiers[i];
            tailClassifier = classifiers[i];
            importedClassifiers.add(tailClassifier);
        }

        return classifiers[0];
    }

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Ensure at least one FatalExceptionClassifier is passed to createChain.
  2. If the chain is built dynamically, guard with: if (classifiers.isEmpty()) { return empty/no-op classifier; } before calling createChain.
  3. Review the caller to ensure the classifier list is always populated with at least one element.

Example fix

// before — dynamic list might be empty
FatalExceptionClassifier.createChain(classifiers.toArray(new FatalExceptionClassifier[0]));
// after — guard against empty
if (classifiers.isEmpty()) {
    throw new IllegalStateException("At least one classifier required");
}
FatalExceptionClassifier.createChain(classifiers.toArray(new FatalExceptionClassifier[0]));
Defensive patterns

Strategy: validation

Validate before calling

// Validate before calling createChain
if (classifiers == null || classifiers.length == 0) {
    throw new IllegalArgumentException("At least one FatalExceptionClassifier is required");
}
FatalExceptionClassifier.createChain(classifiers);

Try / catch

try {
    FatalExceptionClassifier.createChain(classifiers.toArray(new FatalExceptionClassifier[0]));
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("empty classifier chain")) {
        // provide a default classifier or skip chaining
    }
}

Prevention

When it happens

Trigger: Calling FatalExceptionClassifier.createChain() with no varargs arguments, or passing an empty array — e.g., createChain(new FatalExceptionClassifier[0]).

Common situations: A sink implementation builds its classifier chain dynamically from a list that happens to be empty; a configuration error causes all classifiers to be filtered out before createChain is called; defensive programming that constructs the chain from a collection without checking emptiness.

Related errors


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/da5d4a409160e1c9. Report an issue: GitHub.