{"record":{"id":"fbd5fb1be45f7162","repo":"eclipse-vertx/vert.x","slug":"cannot-be-called-on-a-vert-x-worker-thread-canno","errorCode":null,"errorMessage":"Cannot be called on a Vert.x worker thread / Cannot be called on a Vert.x event-loop thread","messagePattern":"Cannot be called on a Vert\\.x worker thread / Cannot be called on a Vert\\.x event-loop thread","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"vertx-core/src/main/java/io/vertx/core/impl/WorkerExecutor.java","lineNumber":33,"sourceCode":"import io.vertx.core.internal.WorkerPool;\nimport io.vertx.core.spi.metrics.PoolMetrics;\n\nimport java.util.concurrent.CountDownLatch;\n\n/**\n * Execute events on a worker pool.\n *\n * @author <a href=\"mailto:julien@julienviet.com\">Julien Viet</a>\n */\npublic class WorkerExecutor implements EventExecutor {\n\n  public static io.vertx.core.impl.WorkerExecutor unwrapWorkerExecutor() {\n    Thread thread = Thread.currentThread();\n    if (thread instanceof VertxThread) {\n      VertxThread vertxThread = (VertxThread) thread;\n      String msg = vertxThread.isWorker() ? \"Cannot be called on a Vert.x worker thread\" :\n        \"Cannot be called on a Vert.x event-loop thread\";\n      throw new IllegalStateException(msg);\n    }\n    ContextInternal ctx = VertxImpl.currentContext(thread);\n    if (ctx != null && ctx.inThread()) {\n      // It can only be a Vert.x virtual thread\n      return (io.vertx.core.impl.WorkerExecutor) ctx.executor();\n    } else {\n      return null;\n    }\n  }\n\n  private final WorkerPool workerPool;\n  private final WorkerTaskQueue orderedTasks;\n  private final ThreadLocal<Boolean> inThread = new ThreadLocal<>();\n\n  public WorkerExecutor(WorkerPool workerPool, WorkerTaskQueue orderedTasks) {\n    this.workerPool = workerPool;\n    this.orderedTasks = orderedTasks;\n  }","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/eclipse-vertx/vert.x/blob/fb308bd8c3f12c79f4ae89bef67fadf6c80d036e/vertx-core/src/main/java/io/vertx/core/impl/WorkerExecutor.java#L15-L51","documentation":"executeBlocking-style worker calls must not be made from Vert.x worker or event-loop threads (you would deadlock or violate the threading model). WorkerExecutor.unwrapWorkerExecutor throws IllegalStateException with a message identifying which thread kind was violated: worker thread or event-loop thread. Only non-Vert.x threads or virtual-thread contexts may obtain the executor this way.","triggerScenarios":"Calling WorkerExecutor API (or APIs delegating to unwrapWorkerExecutor) from inside code running on a VertxThread — i.e. inside a verticle handler, inside another executeBlocking block, or on an event-loop thread.","commonSituations":"Calling executeBlocking inside executeBlocking; invoking worker-pool APIs from a verticle start()/handler; migrating old blocking code that called these APIs directly from an event-loop callback; virtual-thread migration code paths.","solutions":["Do not call executeBlocking/WorkerExecutor from Vert.x worker or event-loop threads — run the work directly or restructure so the blocking call happens on a non-Vert.x thread","If you need to run blocking work from a handler, capture the WorkerExecutor outside and schedule appropriately, or use context.executeBlocking which handles dispatch","For nested blocking logic, await completion via futures rather than nesting worker calls"],"exampleFix":"// before (inside a verticle handler running on event loop)\nWorkerExecutor exec = WorkerExecutor.unwrapWorkerExecutor(); // IllegalStateException\n// after\nWorkerExecutor exec = vertx.createSharedWorkerExecutor(\"my-worker\");\nvertx.executeBlocking(p -> { blockingWork(); p.complete(); }, false, res -> { ... });","handlingStrategy":"type-guard","validationCode":"if (Thread.currentThread() instanceof VertxThread) {\n  throw new IllegalStateException(\"Do not call worker executor APIs from Vert.x threads\");\n}","typeGuard":"boolean safeToExecuteBlocking() {\n  return !(Thread.currentThread() instanceof VertxThread);\n}","tryCatchPattern":"try {\n  WorkerExecutor.unwrapWorkerExecutor();\n} catch (IllegalStateException e) {\n  // restructure: dispatch work via context.executeBlocking instead\n}","preventionTips":["Never nest executeBlocking calls","Only create/unwrap worker executors from non-Vert.x threads or virtual-thread contexts","Use context.executeBlocking when already on a Vert.x context"],"tags":["threading","execute-blocking","worker-pool","event-loop"],"backgroundTag":"invalid-state-transition","analyzedSha":"fb308bd8c3f12c79f4ae89bef67fadf6c80d036e","analyzedAt":"2026-09-06T11:37:12.241Z","contentChangedAt":"2026-09-06T11:37:12.241Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}