apache/seatunnel · error · IllegalStateException
MDCContext is already activated
Error message
MDCContext is already activated
What it means
MDCContext.activate() installs job-id context into the SLF4J MDC and stores the previous context in toRestore. Activating the same MDCContext instance twice without closing it would overwrite toRestore and leak MDC state, so a second activate() on an already-active context throws IllegalStateException. EMPTY contexts are idempotent and exempt.
Source
Thrown at seatunnel-api/src/main/java/org/apache/seatunnel/api/tracing/MDCContext.java:76
private final Long jobId;
private final Long pipelineId;
private final Long taskId;
private transient volatile MDCContext toRestore;
public MDCContext(Long jobId, Long pipelineId, Long taskId) {
this.jobId = jobId;
this.pipelineId = pipelineId;
this.taskId = taskId;
}
public synchronized MDCContext activate() {
if (this == EMPTY) {
return this;
}
if (this.toRestore != null) {
throw new IllegalStateException("MDCContext is already activated");
}
this.toRestore = current();
try {
if (jobId != null) {
MDC.put(JOB_ID, String.valueOf(jobId));
}
if (pipelineId != null) {
MDC.put(PIPELINE_ID, String.valueOf(pipelineId));
}
if (taskId != null) {
MDC.put(TASK_ID, String.valueOf(taskId));
}
} catch (Throwable e) {
log.error("Failed to put MDC context", e);
throw e;
}
return this;View on GitHub (pinned to cf67b549a7)
Solutions
- Activate each MDCContext exactly once, in a try-with-resources block
- Use separate MDCContext instances for nested scopes instead of reusing one
- Check whether an outer layer already activates the context (interceptors/filters) and remove the duplicate call
- If you need re-entrancy, track activation yourself or use the context factory to create a fresh instance per scope
Example fix
// before
MDCContext ctx = new MDCContext(jobId);
try (MDCContext a = ctx.activate()) {
try (MDCContext b = ctx.activate()) { // throws: already activated
// after
MDCContext ctx = new MDCContext(jobId);
try (MDCContext a = ctx.activate()) {
runInner(); // inner code uses ambient MDC, no second activate()
} Defensive patterns
Strategy: try-catch
Validate before calling
// detect double activation before it throws:
// structure code so each MDCContext instance is activated once
try (MDCContext ctx = new MDCContext(jobId).activate()) {
// scope
} Try / catch
try {
mdcContext.activate();
} catch (IllegalStateException e) {
// context already active in this scope — proceed without re-activating
} Prevention
- Always use try-with-resources so close() restores state before reuse
- Create a new MDCContext per scope; never share instances across nested activations
- Audit interceptors/wrappers so only one layer activates the context
- Treat MDCContext as non-reentrant single-use scope handle
When it happens
Trigger: Calling activate() twice on the same non-EMPTY MDCContext instance without close()/restore in between, e.g. wrapping a scope twice or activating in nested try-with-resources blocks sharing one instance.
Common situations: Tracing/observability code that opens the same context scope in both an outer wrapper and inner interceptor; accidental double-activation in job submission paths; reusing a cached MDCContext across sequential code blocks without deactivating.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- MDCContext is not activated
- Already an MDCRunnable
- Already an MDCCallable
- Already an MDCExecutor
- Already an MDCConsumer
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/9af4bc7e64072e3d.
Report an issue: GitHub.