{"record":{"id":"1f4a0c73435d3a4e","repo":"karatelabs/karate","slug":"process-already-started","errorCode":null,"errorMessage":"process already started","messagePattern":"process already started","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"karate-core/src/main/java/io/karatelabs/process/ProcessHandle.java","lineNumber":144,"sourceCode":"    public static ProcessHandle create(ProcessConfig config) {\n        return new ProcessHandle(config);\n    }\n\n    /**\n     * Create and immediately start ProcessHandle.\n     */\n    public static ProcessHandle start(ProcessConfig config) {\n        ProcessHandle handle = new ProcessHandle(config);\n        handle.start();\n        return handle;\n    }\n\n    /**\n     * Start the process. Can only be called once.\n     */\n    public ProcessHandle start() {\n        if (!started.compareAndSet(false, true)) {\n            throw new RuntimeException(\"process already started\");\n        }\n        try {\n            java.lang.ProcessBuilder pb = new java.lang.ProcessBuilder(config.args());\n            if (config.workingDir() != null) {\n                pb.directory(config.workingDir().toFile());\n            }\n            if (!config.env().isEmpty()) {\n                pb.environment().putAll(config.env());\n            }\n            pb.redirectErrorStream(config.redirectErrorStream());\n            logger.debug(\"starting process: {}\", config.args());\n            this.process = pb.start();\n            this.executor = Executors.newVirtualThreadPerTaskExecutor();\n            LIVE_HANDLES.add(this);\n            startStreamReaders();\n            startExitWaiter();\n            return this;\n        } catch (Exception e) {","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-core/src/main/java/io/karatelabs/process/ProcessHandle.java#L126-L162","documentation":"ProcessHandle.start() launches the configured subprocess and is documented as callable only once. It uses an AtomicBoolean compareAndSet to enforce this; a second call finds `started` already true and throws 'process already started'. This is a deliberate state-machine guard, not an OS failure.","triggerScenarios":"Calling start() twice on the same ProcessHandle, or calling a convenience path (fork()/jsGet start) after start() already ran; callers listed include fork, start, jsGet, testOnStdOutChaining, and testDeferredStart.","commonSituations":"Accidentally calling both fork() and start(), re-invoking start() in retry logic, or sharing one ProcessHandle across threads/code paths that each attempt to start it.","solutions":["Call start()/fork() only once per ProcessHandle; store the returned handle and reuse it","If you need a restart, create a new ProcessHandle with the same config instead of re-starting","If start may race, keep a single owner that starts the process and hand the existing handle to other consumers"],"exampleFix":"// before\nhandle.fork();\nhandle.start(); // throws: already started\n// after\nProcessHandle handle = Karate.fork(config); // start once\n// reuse `handle` for listeners, waitForOutput, etc.","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"boolean canStart(ProcessHandle h) {\n    try {\n        java.lang.reflect.Field f = ProcessHandle.class.getDeclaredField(\"started\");\n        f.setAccessible(true);\n        return !((java.util.concurrent.atomic.AtomicBoolean) f.get(h)).get();\n    } catch (Exception e) { return false; }\n}","tryCatchPattern":"try {\n    handle.start();\n} catch (RuntimeException e) {\n    if (!e.getMessage().equals(\"process already started\")) throw e;\n    // already running - reuse existing handle\n}","preventionTips":["Start each handle exactly once at construction; share the started handle","Create a new ProcessHandle per restart instead of reusing","Document single-start contract at the call site"],"tags":["process","state","invalid-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}