{"record":{"id":"9dce1d7e245919a1","repo":"quarkusio/quarkus","slug":"the-vert-x-context-to-attach-the-opentelemetry-con","errorCode":null,"errorMessage":"The Vert.x Context to attach the OpenTelemetry Context must be a duplicated Context","messagePattern":"The Vert\\.x Context to attach the OpenTelemetry Context must be a duplicated Context","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/QuarkusContextStorage.java","lineNumber":60,"sourceCode":"        return vertxContext != null && isDuplicatedContext(vertxContext) ? attach(vertxContext, otelToAttach)\n                : FALLBACK_CONTEXT_STORAGE.attach(otelToAttach);\n    }\n\n    /**\n     * Attach the OpenTelemetry Context in the Vert.x Context if it is a duplicated Vert.x Context.\n     *\n     * @param vertxContext the Vert.x Context to attach the OpenTelemetry Context\n     * @param otelToAttach the OpenTelemetry Context to attach\n     * @return the Scope of the OpenTelemetry Context\n     */\n    public Scope attach(io.vertx.core.Context vertxContext, Context otelToAttach) {\n        if (vertxContext == null || otelToAttach == null) {\n            return Scope.noop();\n        }\n\n        // We don't allow to attach the OpenTelemetry Context to a Vert.x Context that is not a duplicate.\n        if (!isDuplicatedContext(vertxContext)) {\n            throw new IllegalArgumentException(\n                    \"The Vert.x Context to attach the OpenTelemetry Context must be a duplicated Context\");\n        }\n\n        Context otelBeforeAttach = getOtelContext(vertxContext);\n        if (otelToAttach == otelBeforeAttach) {\n            return Scope.noop();\n        }\n\n        if (log.isDebugEnabled()) {\n            log.debugv(\"Setting Otel context: {0}\", OpenTelemetryUtil.getSpanData(otelToAttach));\n        }\n\n        VertxContext.localContextData(vertxContext).put(OTEL_CONTEXT, otelToAttach);\n        OpenTelemetryUtil.setMDCData(otelToAttach, vertxContext);\n\n        return new Scope() {\n\n            @Override","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/opentelemetry/runtime/src/main/java/io/quarkus/opentelemetry/runtime/QuarkusContextStorage.java#L42-L78","documentation":"QuarkusContextStorage (the OpenTelemetry Context storage backed by Vert.x) only permits attaching an OpenTelemetry Context to a Vert.x Context that is a duplicated context (a child context forked per-request/operation). Attaching to a root/unduplicated context would leak traces across requests, so the storage throws IllegalArgumentException('The Vert.x Context to attach the OpenTelemetry Context must be a duplicated Context').","triggerScenarios":"Calling QuarkusContextStorage.attach(vertxContext, otelContext) with a Vert.x Context obtained outside a duplicated scope — e.g. Context from vertx.getOrCreateContext() on an event loop, a root context, or manual Context duplication skipped — while instrumenting code with OpenTelemetry scope management.","commonSituations":"Custom instrumentation or third-party libraries calling Context.current().with(...) and storage.attach(...) on a non-duplicated Vert.x context; running blocking/worker code that grabbed the wrong context; misuse of Vertx.currentContext() in startup or background threads.","solutions":["Ensure the Vert.x context is duplicated before attaching: call context.duplicate() and attach to the duplicated instance","Only attach OTel contexts inside request-scoped/duplicated Vert.x contexts (e.g. within a route handler), not on root contexts","Wrap work in vertx.executeBlocking or route handlers that Quarkus has already duplicated the context for","Refactor custom instrumentation to use Context.root().with(...) capture inside the duplicated scope rather than attaching globally"],"exampleFix":"// before\nContext vertxCtx = vertx.getOrCreateContext();\nScope scope = contextStorage.attach(vertxCtx, otelCtx);\n// after\nContext vertxCtx = vertx.getOrCreateContext().duplicate();\nScope scope = contextStorage.attach(vertxCtx, otelCtx);","handlingStrategy":"type-guard","validationCode":"// check before attaching\nstatic boolean safeToAttach(Context vertxContext) {\n    return vertxContext != null\n        && vertxContext.getLocal(\"__quarkus_otel_duplicated\", false);\n    // or use OrderedMarkers/duplication marker via\n    // VertxContext.isDuplicatedContext(vertxContext) equivalent\n}","typeGuard":"static boolean isDuplicatedContext(Context ctx) {\n    // mirrors QuarkusContextStorage's own check: duplicated contexts carry\n    // the duplication marker local\n    return ctx != null\n        && ctx.getLocal(\"__vertx.duplicated\", false);\n}","tryCatchPattern":"try {\n    scope = contextStorage.attach(vertxContext, otelContext);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"duplicated Context\")) {\n        vertxContext = vertxContext.duplicate();\n        scope = contextStorage.attach(vertxContext, otelContext);\n    } else {\n        throw e;\n    }\n}","preventionTips":["Only attach OTel contexts inside route handlers or scopes Quarkus already duplicated","Call context.duplicate() before attaching to a context you obtained yourself","Never attach to vertx.getOrCreateContext() on startup/background threads","Prefer running custom spans inside Vert.x timers/handlers rather than raw threads"],"tags":["opentelemetry","vertx","context","instrumentation"],"backgroundTag":"non-duplicated-vertx-context","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}