apache/flink · error · IllegalArgumentException

Wrong classifier chain; Circular chain of classifiers detect

Error message

Wrong classifier chain; Circular chain of classifiers detected.

What it means

Thrown as an IllegalArgumentException by FatalExceptionClassifier.createChain when the same FatalExceptionClassifier instance appears more than once in the varargs array. createChain builds a singly-linked chain by setting each classifier's chainedClassifier to the next; a duplicate creates a cycle that would cause infinite loops during isFatal traversal. The code detects this using a HashSet of already-imported classifiers.

Source

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

    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. Review the classifier list before calling createChain — ensure each FatalExceptionClassifier instance is unique.
  2. If reusing common classifiers, create distinct instances via withRootCauseOfType rather than sharing references.
  3. Add a deduplication step: new LinkedHashSet<>(Arrays.asList(classifiers)).toArray(...) before createChain.

Example fix

// before — same instance passed twice
FatalExceptionClassifier chain = FatalExceptionClassifier.createChain(
    networkErrorClassifier, timeoutClassifier, networkErrorClassifier);
// after — distinct instances
FatalExceptionClassifier chain = FatalExceptionClassifier.createChain(
    FatalExceptionClassifier.withRootCauseOfType(IOException.class, mapper),
    FatalExceptionClassifier.withRootCauseOfType(TimeoutException.class, mapper));
Defensive patterns

Strategy: validation

Validate before calling

// Validate uniqueness before calling createChain
List<FatalExceptionClassifier> deduped = new ArrayList<>(new LinkedHashSet<>(Arrays.asList(classifiers)));
if (deduped.size() != classifiers.length) {
    throw new IllegalArgumentException("Duplicate classifiers detected in chain");
}
FatalExceptionClassifier.createChain(deduped.toArray(new FatalExceptionClassifier[0]));

Try / catch

try {
    FatalExceptionClassifier.createChain(classifiers);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("Circular chain")) {
        // deduplicate and retry
        FatalExceptionClassifier[] unique = new LinkedHashSet<>(Arrays.asList(classifiers))
            .toArray(new FatalExceptionClassifier[0]);
        FatalExceptionClassifier.createChain(unique);
    }
}

Prevention

When it happens

Trigger: Passing the same classifier instance twice to createChain, e.g., createChain(classifierA, classifierB, classifierA); or accidentally adding a classifier to a list that already contains it.

Common situations: A sink builder programmatically constructs a classifier list and the same instance is added by mistake (aliasing bug); a common base classifier is reused across multiple sink configurations and passed into the same chain.

Related errors


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