{"record":{"id":"3ceacb12d14cd102","repo":"aeron-io/aeron","slug":"must-use-aeron-context-useconductoragentinvoker-true-when","errorCode":null,"errorMessage":"Must use Aeron.Context.useConductorAgentInvoker(true) when Aeron.Context.clientLock(...) is using a NoOpLock","messagePattern":"Must use Aeron\\.Context\\.useConductorAgentInvoker\\(true\\) when Aeron\\.Context\\.clientLock\\(\\.\\.\\.\\) is using a NoOpLock","errorType":"validation","errorClass":"ConfigurationException","httpStatus":null,"severity":"error","filePath":"aeron-client/src/main/java/io/aeron/Aeron.java","lineNumber":1184,"sourceCode":"        /**\n         * This is called automatically by {@link Aeron#connect(Aeron.Context)} and its overloads.\n         * There is no need to call it from a client application. It is responsible for providing default\n         * values for options that are not individually changed through field setters.\n         *\n         * @return this for a fluent API.\n         */\n        @SuppressWarnings(\"checkstyle:methodlength\")\n        public Context conclude()\n        {\n            super.conclude();\n\n            if (null == clientLock)\n            {\n                clientLock = new ReentrantLock();\n            }\n            else if (clientLock instanceof NoOpLock && !useConductorAgentInvoker)\n            {\n                throw new ConfigurationException(\n                    \"Must use Aeron.Context.useConductorAgentInvoker(true) when Aeron.Context.clientLock(...) \" +\n                    \"is using a NoOpLock\");\n            }\n\n            if (null != driverAgentInvoker && !useConductorAgentInvoker)\n            {\n                throw new ConfigurationException(\n                    \"Must use Aeron.Context.useConductorAgentInvoker(true) when Aeron.Context.driverAgentInvoker() \" +\n                    \"is set\");\n            }\n\n            if (clientName.length() > MAX_CLIENT_NAME_LENGTH)\n            {\n                throw new ConfigurationException(\"clientName length must <= \" + MAX_CLIENT_NAME_LENGTH);\n            }\n\n            if (null == epochClock)\n            {","sourceCodeStart":1166,"sourceCodeEnd":1202,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-client/src/main/java/io/aeron/Aeron.java#L1166-L1202","documentation":"Aeron.Context throws this ConfigurationException during configuration when a NoOpLock is set as the client lock via clientLock(...) but useConductorAgentInvoker(true) was not enabled. NoOpLock provides no mutual exclusion, which is only safe when the caller drives the conductor agent directly on the same thread (agent invoker mode); otherwise concurrent access is unsafe, so the combination is rejected.","triggerScenarios":"Building a Context with ctx.clientLock(new NoOpLock()) (or ctx.clientLock(true) equivalent) without also calling ctx.useConductorAgentInvoker(true), then calling Aeron.connect(ctx).","commonSituations":"Low-latency setups that eliminate locking to avoid contention but forget to switch to conductor agent invoker mode; copying a dedicated-mode config into a client that still uses the driver thread; upgrades where NoOpLock was introduced and existing configs were not updated.","solutions":["Call ctx.useConductorAgentInvoker(true) on the same Context that uses NoOpLock","Remove the NoOpLock and use the default ReentrantLock if you want the normal client thread mode","Use the Convenience/ Configuration helper that pairs clientLock(true) with useConductorAgentInvoker(true) consistently"],"exampleFix":"// before\nAeron.Context ctx = new Aeron.Context()\n    .clientLock(new NoOpLock());\nAeron aeron = Aeron.connect(ctx); // throws\n// after\nAeron.Context ctx = new Aeron.Context()\n    .clientLock(new NoOpLock())\n    .useConductorAgentInvoker(true);\nAeron aeron = Aeron.connect(ctx);","handlingStrategy":"validation","validationCode":"if (ctx instanceof Aeron.Context) { /* ensure pairing before connect */ } // validate: use NoOpLock only together with useConductorAgentInvoker(true)","typeGuard":"boolean lockModeConsistent(Aeron.Context ctx) { return ctx.useConductorAgentInvoker() || !(ctx.clientLock() instanceof NoOpLock); }","tryCatchPattern":"try { return Aeron.connect(ctx); } catch (ConfigurationException e) { if (e.getMessage().contains(\"NoOpLock\")) { ctx.useConductorAgentInvoker(true); return Aeron.connect(ctx); } throw e; }","preventionTips":["Always pair clientLock(new NoOpLock()) with useConductorAgentInvoker(true)","Write a Context factory that enforces the pairing in one place","Never mix dedicated-mode configs with invoker-mode clients"],"tags":["configuration","locking","agent-invoker","no-op-lock"],"backgroundTag":"conflicting-config-options","analyzedSha":"6d60124e15e35c11b49ba2e3c2c2858a09a18803","analyzedAt":"2026-09-12T11:17:07.683Z","contentChangedAt":"2026-09-12T11:17:07.683Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}