{"record":{"id":"6046b1631ab1e1f2","repo":"LMAX-Exchange/disruptor","slug":"failed-to-create-thread-to-run","errorCode":null,"errorMessage":"Failed to create thread to run: {}","messagePattern":"Failed to create thread to run: (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/main/java/com/lmax/disruptor/dsl/EventProcessorInfo.java","lineNumber":71,"sourceCode":"    @Override\n    public SequenceBarrier getBarrier()\n    {\n        return barrier;\n    }\n\n    @Override\n    public boolean isEndOfChain()\n    {\n        return endOfChain;\n    }\n\n    @Override\n    public void start(final ThreadFactory threadFactory)\n    {\n        final Thread thread = threadFactory.newThread(eventprocessor);\n        if (null == thread)\n        {\n            throw new RuntimeException(\"Failed to create thread to run: \" + eventprocessor);\n        }\n\n        thread.start();\n    }\n\n    @Override\n    public void halt()\n    {\n        eventprocessor.halt();\n    }\n\n    /**\n     *\n     */\n    @Override\n    public void markAsUsedInBarrier()\n    {\n        endOfChain = false;","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/LMAX-Exchange/disruptor/blob/c871ca49826a6be7ada6957f6fbafcfecf7b1f87/src/main/java/com/lmax/disruptor/dsl/EventProcessorInfo.java#L53-L89","documentation":"Thrown by EventProcessorInfo.start (src/main/java/com/lmax/disruptor/dsl/EventProcessorInfo.java:71) when the ThreadFactory supplied to Disruptor.start(threadFactory) returns null from newThread(). The Disruptor DSL starts each event processor by asking the factory for a thread and calling thread.start(); a null return is treated as a broken factory configuration. It is an unchecked guard against misconfigured thread creation, not a transient failure.","triggerScenarios":"Calling disruptor.start(customThreadFactory) where customThreadFactory.newThread(runnable) returns null (e.g. a factory that conditionally creates threads, wraps Executors.defaultThreadFactory() but forwards a null field, or a factory whose backing pool is shut down and coded to return null). Also passing a mocked ThreadFactory in tests that is not stubbed for newThread (Mockito default returns null).","commonSituations":"Custom ThreadFactory for naming/daemon threads that has a null-returning branch; unit tests of the DSL wiring with an un-stubbed mock factory; dependency-injection setups where the factory bean is optional and resolves to null-returning lambda; upgrading code that previously used the no-arg start() and later passes a hand-written factory.","solutions":["Make the custom ThreadFactory always return a non-null Thread; delegate to Executors.defaultThreadFactory().newThread(runnable) and then rename/customize the returned thread.","If the factory came from a DI container or mock, fix the wiring/stubbing so newThread returns a real Thread (e.g. Mockito when(factory.newThread(any())).thenAnswer(inv -> new Thread(inv.getArgument(0)))).","Audit every return path (including error paths) of the factory lambda for accidental null returns; prefer throwing inside the factory if creation genuinely fails instead of returning null.","As a stopgap, use disruptor.start() with no factory (BasicValidator/Disruptor uses Executors.defaultThreadFactory()) to confirm the rest of the wiring is correct before re-adding the custom factory."],"exampleFix":"// before\nThreadFactory tf = r -> shouldCreateThreads ? new Thread(r) : null; // null branch -> RuntimeException at EventProcessorInfo.start\ndisruptor.start(tf);\n\n// after\nThreadFactory tf = r -> {\n    Thread t = new Thread(r);\n    t.setName(\"disruptor-processor\");\n    t.setDaemon(true);\n    return t; // always non-null\n};\ndisruptor.start(tf);","handlingStrategy":"validation","validationCode":"// Before disruptor.start(threadFactory): verify the factory returns a non-null thread\nThread probe = threadFactory.newThread(() -> {});\nif (probe == null) {\n    throw new IllegalStateException(\"ThreadFactory must return a non-null Thread\");\n}","typeGuard":null,"tryCatchPattern":"// If start() is invoked with externally supplied factories, fail fast with context\ntry {\n    disruptor.start(threadFactory);\n} catch (RuntimeException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Failed to create thread\")) {\n        throw new IllegalStateException(\"Disruptor ThreadFactory returned null: \" + threadFactory, e);\n    }\n    throw e;\n}","preventionTips":["Always delegate custom ThreadFactory implementations to Executors.defaultThreadFactory() and only decorate the returned thread (name, daemon, priority).","Never write a null-returning branch in a ThreadFactory; throw on failure instead of returning null.","In tests, stub newThread explicitly: when(factory.newThread(any())).thenAnswer(inv -> new Thread(inv.getArgument(0)));"],"tags":["java","disruptor","thread-factory","configuration","null-check"],"backgroundTag":null,"analyzedSha":"c871ca49826a6be7ada6957f6fbafcfecf7b1f87","analyzedAt":"2026-08-14T14:22:36.358Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}