{"record":{"id":"d11e5728365360cc","repo":"apache/seatunnel","slug":"already-an-mdcexecutor","errorCode":null,"errorMessage":"Already an MDCExecutor","messagePattern":"Already an MDCExecutor","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"seatunnel-api/src/main/java/org/apache/seatunnel/api/tracing/MDCTracer.java","lineNumber":96,"sourceCode":"\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    }\n\n    public static MDCExecutorService tracing(ExecutorService delegate) {\n        return tracing(MDCContext.current(), delegate);\n    }\n\n    public static MDCExecutorService tracing(Long jobId, ExecutorService delegate) {\n        return tracing(MDCContext.of(jobId), delegate);\n    }\n\n    public static MDCExecutorService tracing(MDCContext context, ExecutorService delegate) {\n        if (delegate instanceof MDCExecutor) {\n            throw new IllegalArgumentException(\"Already an MDCExecutor\");\n        }\n        return new MDCExecutorService(context, delegate);\n    }","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-api/src/main/java/org/apache/seatunnel/api/tracing/MDCTracer.java#L78-L114","documentation":"MDCTracer.tracing(context, Executor) rejects a delegate that is already an MDCExecutor with IllegalArgumentException. Double-wrapping an Executor would propagate MDC context through two layers and restore state out of order.","triggerScenarios":"Calling tracing(jobId, executor) or tracing(context, executor) where executor is already an MDCExecutor (possibly from wrapping an ExecutorService, since MDCExecutorService subclasses MDCExecutor).","commonSituations":"An application already returns MDC-wrapped executors from a factory and calling code wraps again; wrapping an MDCExecutorService obtained from tracing(ExecutorService).","solutions":["Reuse the existing MDCExecutor instead of wrapping again","Keep a single wrapping point (executor factory) and never re-trace returned executors","Guard with `if (executor instanceof MDCExecutor) use it else tracing(...)`"],"exampleFix":"// before\nMDCExecutor e = MDCTracer.tracing(jobId, MDCTracer.tracing(jobId, pool));\n// after\nMDCExecutor e = MDCTracer.tracing(jobId, pool);","handlingStrategy":"type-guard","validationCode":"Executor safeWrap(Long jobId, Executor e) {\n    return e instanceof MDCExecutor ? e : MDCTracer.tracing(jobId, e);\n}","typeGuard":"boolean isWrapped(Executor e) {\n    return e instanceof MDCExecutor;\n}","tryCatchPattern":"try {\n    return MDCTracer.tracing(jobId, executor);\n} catch (IllegalArgumentException e) {\n    return (MDCExecutor) executor;\n}","preventionTips":["Wrap executors once in a central factory","Never re-trace executors returned by another module","Remember MDCExecutorService/MDCScheduledExecutorService also satisfy the instanceof check"],"tags":["java","mdc","tracing","double-wrap","executor"],"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"}