apache/seatunnel · error · IllegalArgumentException
Already an MDCFunction
Error message
Already an MDCFunction
What it means
MDCTracer.tracing(context, Function) rejects a delegate already wrapped as MDCFunction with IllegalArgumentException. This prevents nested MDC capture/restore around a single function application, which would restore stale state.
Source
Thrown at seatunnel-api/src/main/java/org/apache/seatunnel/api/tracing/MDCTracer.java:158
public static <T> MDCConsumer<T> tracing(MDCContext context, Consumer<T> delegate) {
if (delegate instanceof MDCConsumer) {
throw new IllegalArgumentException("Already an MDCConsumer");
}
return new MDCConsumer<>(context, delegate);
}
public static <T, R> MDCFunction<T, R> tracing(Function<T, R> delegate) {
return tracing(MDCContext.current(), delegate);
}
public static <T, R> MDCFunction<T, R> tracing(Long jobId, Function<T, R> delegate) {
return tracing(MDCContext.of(jobId), delegate);
}
public static <T, R> MDCFunction<T, R> tracing(MDCContext context, Function<T, R> delegate) {
if (delegate instanceof MDCFunction) {
throw new IllegalArgumentException("Already an MDCFunction");
}
return new MDCFunction<>(context, delegate);
}
public static <T> MDCPredicate<T> tracing(Predicate<T> delegate) {
return tracing(MDCContext.current(), delegate);
}
public static <T> MDCPredicate<T> tracing(Long jobId, Predicate<T> delegate) {
return tracing(MDCContext.of(jobId), delegate);
}
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);
}View on GitHub (pinned to cf67b549a7)
Solutions
- Trace the Function once at the outermost composition point
- Pass through already-traced instances: `if (f instanceof MDCFunction) return f;`
- Unwrap the duplicated tracing call in one of the layers
Example fix
// before MDCFunction<T,R> f = MDCTracer.tracing(jobId, MDCTracer.tracing(jobId, fn)); // after MDCFunction<T,R> f = MDCTracer.tracing(jobId, fn);
Defensive patterns
Strategy: type-guard
Validate before calling
MDCFunction<T,R> safeWrap(Long jobId, Function<T,R> f) {
return f instanceof MDCFunction ? (MDCFunction<T,R>) f : MDCTracer.tracing(jobId, f);
} Type guard
boolean isWrapped(Function<?,?> f) {
return f instanceof MDCFunction;
} Try / catch
try {
return MDCTracer.tracing(jobId, function);
} catch (IllegalArgumentException e) {
return (MDCFunction<T,R>) function;
} Prevention
- Trace functions once at composition time
- Avoid caching traced functions and wrapping them again on reuse
- Use an instanceof MDCFunction pass-through guard in mapping helpers
When it happens
Trigger: Calling tracing(jobId, function) or tracing(context, function) where function is already an MDCFunction from a previous tracing() call, e.g. mapping functions wrapped by both a transform utility and the caller.
Common situations: Transform chains where map() helpers and the engine both trace the same Function; caching traced functions and re-tracing.
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 MDCRunnable
- Already an MDCCallable
- Already an MDCExecutor
- Already an MDCConsumer
- Already an MDCPredicate
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/89a181a7152ae364.
Report an issue: GitHub.