{"record":{"id":"d7b8b0927127fb89","repo":"apache/seatunnel","slug":"already-an-mdccallable","errorCode":null,"errorMessage":"Already an MDCCallable","messagePattern":"Already an MDCCallable","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"seatunnel-api/src/main/java/org/apache/seatunnel/api/tracing/MDCTracer.java","lineNumber":81,"sourceCode":"\n    public static MDCRunnable tracing(MDCContext context, Runnable delegate) {\n        if (delegate instanceof MDCRunnable) {\n            throw new IllegalArgumentException(\"Already an MDCRunnable\");\n        }\n        return new MDCRunnable(context, delegate);\n    }\n\n    public static <V> MDCCallable<V> tracing(Callable<V> delegate) {\n        return tracing(MDCContext.current(), delegate);\n    }\n\n    public static <V> MDCCallable<V> tracing(Long jobId, Callable<V> delegate) {\n        return tracing(MDCContext.of(jobId), delegate);\n    }\n\n    public static <V> MDCCallable<V> tracing(MDCContext context, Callable<V> delegate) {\n        if (delegate instanceof MDCCallable) {\n            throw new IllegalArgumentException(\"Already an MDCCallable\");\n        }\n        return new MDCCallable<>(context, delegate);\n    }\n\n    public static MDCExecutor tracing(Executor delegate) {\n        return tracing(MDCContext.current(), delegate);\n    }\n\n    public static MDCExecutor tracing(Long jobId, Executor delegate) {\n        return tracing(MDCContext.of(jobId), delegate);\n    }\n\n    public static MDCExecutor tracing(MDCContext context, Executor delegate) {\n        if (delegate instanceof MDCExecutor) {\n            throw new IllegalArgumentException(\"Already an MDCExecutor\");\n        }\n        return new MDCExecutor(context, delegate);\n    }","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-api/src/main/java/org/apache/seatunnel/api/tracing/MDCTracer.java#L63-L99","documentation":"MDCTracer.tracing(context, Callable) rejects a delegate already wrapped as MDCCallable via IllegalArgumentException. It prevents nested MDC wrapping of Callables, which would snapshot/restore the wrong MDC state on completion.","triggerScenarios":"Calling tracing(jobId, callable) or tracing(context, callable) where callable is already an MDCCallable from a previous tracing() call.","commonSituations":"Double-wrapping tasks submitted through both a helper utility and the executor wrapper; caching already-traced Callables and re-tracing them.","solutions":["Trace the Callable only once, at the outermost layer","Guard with `if (delegate instanceof MDCCallable) use it else tracing(...)`","Strip the earlier wrap and pass the unwrapped Callable"],"exampleFix":"// before\nMDCCallable<V> c = MDCTracer.tracing(jobId, MDCTracer.tracing(jobId, call));\n// after\nMDCCallable<V> c = MDCTracer.tracing(jobId, call);","handlingStrategy":"type-guard","validationCode":"MDCCallable<V> safeWrap(Long jobId, Callable<V> c) {\n    return c instanceof MDCCallable ? (MDCCallable<V>) c : MDCTracer.tracing(jobId, c);\n}","typeGuard":"boolean isWrapped(Callable<?> c) {\n    return c instanceof MDCCallable;\n}","tryCatchPattern":"try {\n    return MDCTracer.tracing(jobId, callable);\n} catch (IllegalArgumentException e) {\n    return (MDCCallable<V>) callable;\n}","preventionTips":["Trace Callables at one layer only","Do not re-wrap cached or previously submitted traced Callables","Check instanceof MDCCallable before wrapping at boundaries"],"tags":["java","mdc","tracing","double-wrap"],"backgroundTag":"invalid-argument-value","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}