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
- Pass the already-wrapped MDCSupplier directly instead of re-tracing it (MDCSupplier IS-A Supplier, so it can be used as-is)
- Remove the redundant tracing() call at one of the two layers
- 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
- Wrap once at the pipeline boundary, not at every layer
- Use a helper like ensureTraced instead of calling tracing unconditionally
- Search call graph for multiple tracing() applications to the same supplier
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
- Already an MDCStream
- MDCContext is already activated
- MDCContext is not activated
- Already an MDCRunnable
- Already an MDCCallable
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/6ef827076f3e14d2.
Report an issue: GitHub.