apache/seatunnel · error · IllegalArgumentException

Already an MDCComparator

Error message

Already an MDCComparator

What it means

MDCTracer.tracing(context, Comparator) rejects a delegate already wrapped as MDCComparator with IllegalArgumentException. Double wrapping would snapshot/restore MDC state twice around a single comparison, corrupting restoration order.

Solutions

  1. Trace the Comparator once, at the point where it is created
  2. Pass through already-wrapped comparators: `if (c instanceof MDCComparator) return c;`
  3. Deduplicate tracing across the utility and call-site layers

Example fix

// before
MDCComparator<T> c = MDCTracer.tracing(jobId, MDCTracer.tracing(jobId, cmp));
// after
MDCComparator<T> c = MDCTracer.tracing(jobId, cmp);
Defensive patterns

Strategy: type-guard

Validate before calling

MDCComparator<T> safeWrap(Long jobId, Comparator<T> c) {
    return c instanceof MDCComparator ? (MDCComparator<T>) c : MDCTracer.tracing(jobId, c);
}

Type guard

boolean isWrapped(Comparator<?> c) {
    return c instanceof MDCComparator;
}

Try / catch

try {
    return MDCTracer.tracing(jobId, comparator);
} catch (IllegalArgumentException e) {
    return (MDCComparator<T>) comparator;
}

Prevention

When it happens

Trigger: Calling tracing(jobId, comparator) or tracing(context, comparator) where comparator is already an MDCComparator from a previous tracing() call, e.g. sort comparators wrapped by both a sort utility and the caller.

Common situations: Sorting/merging code where a shared comparator factory already applies tracing and the call site wraps again.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at seatunnel-api/src/main/java/org/apache/seatunnel/api/tracing/MDCTracer.java:188

    public static <T> MDCPredicate<T> tracing(MDCContext context, Predicate<T> delegate) {
        if (delegate instanceof MDCPredicate) {
            throw new IllegalArgumentException("Already an MDCPredicate");
        }
        return new MDCPredicate<>(context, delegate);
    }

    public static <T> MDCComparator<T> tracing(Comparator<T> delegate) {
        return tracing(MDCContext.current(), delegate);
    }

    public static <T> MDCComparator<T> tracing(Long jobId, Comparator<T> delegate) {
        return tracing(MDCContext.of(jobId), delegate);
    }

    public static <T> MDCComparator<T> tracing(MDCContext context, Comparator<T> delegate) {
        if (delegate instanceof MDCComparator) {
            throw new IllegalArgumentException("Already an MDCComparator");
        }
        return new MDCComparator<>(context, delegate);
    }

    public static <T> MDCSupplier<T> tracing(Supplier<T> delegate) {
        return tracing(MDCContext.current(), delegate);
    }

    public static <T> MDCSupplier<T> tracing(Long jobId, Supplier<T> delegate) {
        return tracing(MDCContext.of(jobId), delegate);
    }

    public static <T> MDCSupplier<T> tracing(MDCContext context, Supplier<T> delegate) {
        if (delegate instanceof MDCSupplier) {
            throw new IllegalArgumentException("Already an MDCSupplier");
        }
        return new MDCSupplier<>(context, delegate);
    }

View on GitHub (pinned to cf67b549a7)