apache/seatunnel · error · IllegalArgumentException

Already an MDCSupplier

Error message

Already an MDCSupplier

What it means

MDCTracer.tracing(MDCContext, Supplier) wraps a plain Supplier in an MDCSupplier so trace context (jobId) propagates via MDC during supply(). It refuses to double-wrap: if the delegate is already an MDCSupplier it throws IllegalArgumentException, since wrapping again would nest contexts and defeat the tracing contract.

Source

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

    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);
    }

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

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

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

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Pass the already-wrapped MDCSupplier directly instead of re-tracing it (MDCSupplier IS-A Supplier, so it can be used as-is)
  2. Remove the redundant tracing() call at one of the two layers
  3. Unwrap the delegate first if you need to change the context, e.g. use MDCTracer.tracing(newContext, existingSupplier.getDelegate()) if available

Example fix

// before
Supplier<String> traced = MDCTracer.tracing(jobId, supplier);
Supplier<String> again = MDCTracer.tracing(jobId, traced); // throws
// after
Supplier<String> traced = MDCTracer.tracing(jobId, supplier); // wrap once
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(supplier instanceof MDCSupplier)) { supplier = MDCTracer.tracing(jobId, supplier); }

Type guard

static <T> Supplier<T> ensureTraced(Supplier<T> s, Long jobId) { return s instanceof MDCSupplier ? s : MDCTracer.tracing(jobId, s); }

Try / catch

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

Prevention

When it happens

Trigger: Calling MDCTracer.tracing(context, supplier) where the supplier argument is already an instance of MDCSupplier — typically when tracing is applied twice, e.g. a supplier created by tracing(jobId, s) is later passed to tracing again.

Common situations: Pipelining supplier factories that each add tracing; refactoring code where an upstream layer already wrapped the supplier; caching a traced supplier and re-tracing it in a second component.

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/6ef827076f3e14d2. Report an issue: GitHub.