apache/seatunnel · error · IllegalStateException
MDCContext is not activated
Error message
MDCContext is not activated
What it means
MDCContext tracks whether it was activated (toRestore set to the prior MDC map). deactivate() throws IllegalStateException when called on a context that was never activated via activate(), or that was already deactivated (toRestore nulled afterwards). This guards against unbalanced activate/deactivate pairs corrupting thread-local MDC state.
Source
Thrown at seatunnel-api/src/main/java/org/apache/seatunnel/api/tracing/MDCContext.java:103
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;
}
public synchronized MDCContext deactivate() {
if (this == EMPTY) {
return this;
}
if (this.toRestore == null) {
throw new IllegalStateException("MDCContext is not activated");
}
try {
MDC.remove(JOB_ID);
MDC.remove(PIPELINE_ID);
MDC.remove(TASK_ID);
} catch (Throwable e) {
log.error("Failed to clear MDC context", e);
throw e;
}
if (this.toRestore != null) {
this.toRestore.activate();
}
return this;
}
View on GitHub (pinned to cf67b549a7)
Solutions
- Ensure activate() is called before deactivate(), e.g. use try-with-resources: context.activate() then try-with-resources on the returned context
- Remove the duplicate deactivate()/close() call on the same MDCContext instance
- Use MDCContext.of(jobId) only with MDCTracer.tracing(...) wrappers instead of manual activate/deactivate
Example fix
// before
MDCContext ctx = MDCContext.of(jobId);
ctx.deactivate(); // throws: never activated
// after
try (MDCContext ctx = MDCContext.of(jobId).activate()) {
// job id in MDC
} // close() deactivates exactly once Defensive patterns
Strategy: try-catch
Validate before calling
// before deactivating
if (ctx != MDCContext.EMPTY && isActivated(ctx)) {
ctx.deactivate();
} Type guard
boolean isActivated(MDCContext ctx) {
return ctx != null && ctx != MDCContext.EMPTY;
} Try / catch
try {
ctx.deactivate();
} catch (IllegalStateException e) {
log.warn("MDCContext deactivate called without matching activate", e);
} Prevention
- Always use try-with-resources around MDCContext.activate() so close() balances activation
- Never call deactivate() twice on the same context
- Prefer MDCTracer.tracing(...) wrappers over manual activate/deactivate
- Treat MDCContext as opaque; do not copy or reuse instances across threads
When it happens
Trigger: Calling deactivate() on MDCContext.EMPTY (returns this, no throw) is safe, but calling deactivate() on a fresh MDCContext.of(jobId) without a prior activate(), or a second deactivate() after the first already restored and cleared toRestore.
Common situations: Double-closing an MDCContext (close() calls deactivate, so closing twice or closing a context that was never activated); manual lifecycle code where activate() failed or was skipped; passing a non-activated context into try-with-resources.
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
- Already an MDCRunnable
- Already an MDCCallable
- Already an MDCExecutor
- Already an MDCConsumer
- Already an MDCFunction
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/c16aeafe8c0dfcb1.
Report an issue: GitHub.