apache/seatunnel · error · IllegalArgumentException
Already an MDCRunnable
Error message
Already an MDCRunnable
What it means
MDCTracer.tracing(context, Runnable) rejects a delegate that is already an MDCRunnable. Wrapping twice would apply MDC context twice and restore it incorrectly, so the library fails fast with IllegalArgumentException.
Source
Thrown at seatunnel-api/src/main/java/org/apache/seatunnel/api/tracing/MDCTracer.java:66
* logger.info("Task is running");
* return null;
* }));
*
* }</pre>
*/
public class MDCTracer {
public static MDCRunnable tracing(Runnable delegate) {
return tracing(MDCContext.current(), delegate);
}
public static MDCRunnable tracing(Long jobId, Runnable delegate) {
return tracing(MDCContext.of(jobId), delegate);
}
public static MDCRunnable tracing(MDCContext context, Runnable delegate) {
if (delegate instanceof MDCRunnable) {
throw new IllegalArgumentException("Already an MDCRunnable");
}
return new MDCRunnable(context, delegate);
}
public static <V> MDCCallable<V> tracing(Callable<V> delegate) {
return tracing(MDCContext.current(), delegate);
}
public static <V> MDCCallable<V> tracing(Long jobId, Callable<V> delegate) {
return tracing(MDCContext.of(jobId), delegate);
}
public static <V> MDCCallable<V> tracing(MDCContext context, Callable<V> delegate) {
if (delegate instanceof MDCCallable) {
throw new IllegalArgumentException("Already an MDCCallable");
}
return new MDCCallable<>(context, delegate);
}View on GitHub (pinned to cf67b549a7)
Solutions
- Pass the raw Runnable to tracing() only once
- If the delegate may already be wrapped, check `if (delegate instanceof MDCRunnable)` and use it directly instead of wrapping again
- Remove the inner tracing() call at one of the layers
Example fix
// before MDCRunnable r = MDCTracer.tracing(jobId, MDCTracer.tracing(jobId, task)); // after MDCRunnable r = MDCTracer.tracing(jobId, task);
Defensive patterns
Strategy: type-guard
Validate before calling
MDCRunnable safeWrap(Long jobId, Runnable r) {
return r instanceof MDCRunnable ? (MDCRunnable) r : MDCTracer.tracing(jobId, r);
} Type guard
boolean isWrapped(Runnable r) {
return r instanceof MDCRunnable;
} Try / catch
try {
return MDCTracer.tracing(jobId, runnable);
} catch (IllegalArgumentException e) {
return (MDCRunnable) runnable;
} Prevention
- Wrap a Runnable with tracing() exactly once, at a single ownership layer
- Never re-trace runtimes returned by tracing()
- Use the safeWrap helper at API boundaries where provenance is unknown
When it happens
Trigger: Calling MDCTracer.tracing(jobId, runnable) or tracing(context, runnable) where runnable is already the result of a previous tracing() call, e.g. double-wrapping in shared submission code or a scheduler that wraps tasks twice.
Common situations: A task wrapper layer and an executor layer both call MDCTracer.tracing on the same Runnable; refactors that moved tracing to an outer layer without removing the inner call.
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 MDCCallable
- Already an MDCExecutor
- Already an MDCConsumer
- Already an MDCFunction
- Already an MDCPredicate
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/336404aba610eeb9.
Report an issue: GitHub.