{"record":{"id":"82af34d1b4eb48b7","repo":"karatelabs/karate","slug":"process-timed-out-after-ms","errorCode":null,"errorMessage":"process timed out after ms","messagePattern":"process timed out after ms","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"karate-core/src/main/java/io/karatelabs/process/ProcessHandle.java","lineNumber":342,"sourceCode":"    public int waitSync() {\n        try {\n            int code = exitFuture.get();\n            // Wait for stream readers to complete so all output is captured\n            waitForStreamReaders();\n            return code;\n        } catch (Exception e) {\n            throw new RuntimeException(\"error waiting for process\", e);\n        }\n    }\n\n    public int waitSync(long timeoutMillis) {\n        try {\n            int code = exitFuture.get(timeoutMillis, TimeUnit.MILLISECONDS);\n            // Wait for stream readers to complete so all output is captured\n            waitForStreamReaders();\n            return code;\n        } catch (TimeoutException e) {\n            throw new RuntimeException(\"process timed out after \" + timeoutMillis + \"ms\");\n        } catch (Exception e) {\n            throw new RuntimeException(\"error waiting for process\", e);\n        }\n    }\n\n    /**\n     * Wait for all stream reader threads to complete.\n     * This ensures all output is captured before getStdOut()/getStdErr() is called.\n     * <p>\n     * After process exit, stream readers complete almost instantly since the OS\n     * closes the pipes. We use a short timeout as a safety net.\n     */\n    private void waitForStreamReaders() {\n        try {\n            // Streams close immediately after process exit, so this should be near-instant.\n            // Use 500ms timeout as safety net (never hit in practice).\n            if (stdoutReaderDone != null && !stdoutReaderDone.isDone()) {\n                stdoutReaderDone.get(500, TimeUnit.MILLISECONDS);","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-core/src/main/java/io/karatelabs/process/ProcessHandle.java#L324-L360","documentation":"The timed waitSync(timeoutMillis) waits for process exit within a deadline; if the process has not exited when the deadline passes, it throws 'process timed out after <n>ms' as a TimeoutException-driven RuntimeException. This is the deliberate timeout signal for runaway subprocesses.","triggerScenarios":"Calling waitSync(timeoutMillis) (directly or via exec/jsGet) when the subprocess runs longer than the given timeout - e.g. a server that never stops, a hung CLI waiting for stdin, or an unreasonably small timeout value.","commonSituations":"Forking a dev server for integration tests that keeps running instead of exiting, CLI tools prompting for input, slow startup on CI, or forgetting that long-lived processes never 'exit' and should be waited on differently.","solutions":["Increase the timeout to match realistic process duration, especially on slower CI machines","Fix the subprocess so it terminates (close stdin, send a stop signal, or kill it) instead of waiting indefinitely","If the process is meant to be long-lived (server), don't waitSync - use waitForOutput/readyLine to wait for readiness, then stop it explicitly","Check whether the process is blocked on stdin/stdout backpressure; consume or redirect its streams"],"exampleFix":"// before\nhandle.waitSync(5_000); // server process never exits -> timeout\n// after\nhandle.waitForOutput(\"started\", 30_000); // wait for readiness line\n// ... run tests ...\nhandle.stop(10_000); // then terminate explicitly","handlingStrategy":"retry","validationCode":"long elapsed = System.currentTimeMillis() - startNanos;\nif (expectedMaxRuntimeMs > 0 && elapsed > expectedMaxRuntimeMs) { /* warn early */ }","typeGuard":null,"tryCatchPattern":"try {\n    handle.waitSync(30_000);\n} catch (RuntimeException e) {\n    if (e.getMessage().startsWith(\"process timed out after\")) {\n        handle.stop(5_000); // clean up the runaway process\n    } else {\n        throw e;\n    }\n}","preventionTips":["Size timeouts for CI, not local machines (multiply local duration by 3-5x)","Never waitSync long-lived server processes; use waitForOutput/readyLine for readiness","Always stop() the handle in a finally block to avoid leaks after timeouts","Make subprocesses non-interactive (close stdin, pass -y/--no-input flags)"],"tags":["process","timeout","wait"],"backgroundTag":"request-timeout","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-16T19:17:19.609Z"}