{"record":{"id":"c9ac5c3cfa920edc","repo":"karatelabs/karate","slug":"retry-interrupted","errorCode":null,"errorMessage":"retry interrupted","messagePattern":"retry interrupted","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"karate-core/src/main/java/io/karatelabs/core/StepExecutor.java","lineNumber":2342,"sourceCode":"    }\n\n    private HttpResponse executeMethodWithRetry(String method, String retryUntil, KarateConfig config) {\n        int maxRetries = config.getRetryCount();\n        int sleepInterval = config.getRetryInterval();\n        int retryCount = 0;\n        Suite suite = getSuite();\n\n        while (true) {\n            if (retryCount == maxRetries) {\n                throw new RuntimeException(\"retry failed after \" + maxRetries + \" attempts: \" + retryUntil);\n            }\n            if (retryCount > 0) {\n                try {\n                    logger.debug(\"sleeping {} ms before retry #{}\", sleepInterval, retryCount);\n                    Thread.sleep(sleepInterval);\n                } catch (InterruptedException e) {\n                    Thread.currentThread().interrupt();\n                    throw new RuntimeException(\"retry interrupted\", e);\n                }\n            }\n\n            // Make a copy of the request builder to preserve state for retry\n            HttpRequestBuilder httpCopy = http().copy();\n\n            // Build request for HTTP_ENTER event (method already set in doMethod)\n            HttpRequest request = http().build();\n\n            // Fire HTTP_ENTER event - listener can return false to skip\n            boolean shouldProceed = true;\n            if (suite != null) {\n                shouldProceed = suite.fireEvent(HttpRunEvent.enter(request, runtime));\n            }\n\n            HttpResponse response;\n            if (shouldProceed) {\n                response = http().invoke(method);","sourceCodeStart":2324,"sourceCodeEnd":2360,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-core/src/main/java/io/karatelabs/core/StepExecutor.java#L2324-L2360","documentation":"While sleeping the configured retry interval between `retry until` attempts, the worker thread received an interrupt (InterruptedException). Karate re-asserts the interrupt flag and throws this RuntimeException wrapping the InterruptedException, aborting the retry loop.","triggerScenarios":"A step in `retry until` execution was sleeping between attempts when the thread was interrupted — typically by test-suite shutdown, a JUnit/TestNG timeout, an executor shutdown, or manual cancellation.","commonSituations":"Suite timeouts killing a hung scenario mid-retry; CI pipeline cancellation; shutting down an embedded runner while a retry sleep is in flight.","solutions":["Let the scenario fail; the interrupt means something upstream wants the thread to stop — investigate the source of the cancellation.","Avoid wrapping Karate scenarios in very short outer timeouts that interrupt mid-retry.","If interruption is expected during shutdown, catch and treat it as cancellation rather than a test failure.","Reduce retry counts/intervals so retries complete before any outer timeout fires."],"exampleFix":"// before (runner)\nexecutor.setAwaitTerminationMillis(1000); // interrupts mid-retry\n// after\nexecutor.setAwaitTerminationMillis(60000); // give retry sleeps room to finish","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Wrap retry-heavy scenarios so interruption is distinguishable\ntry {\n    Result r = karate.run(path);\n} catch (RuntimeException e) {\n    if (e.getMessage().equals(\"retry interrupted\") && Thread.currentThread().isInterrupted()) {\n        // expected during shutdown; skip reporting as product failure\n        return;\n    }\n    throw e;\n}","preventionTips":["Avoid short outer timeouts that interrupt threads mid-retry-sleep.","Coordinate shutdown: cancel scenarios before terminating the executor.","Keep retry sleeps small relative to the runner's await/termination budget.","Don't reuse interrupted threads for subsequent runs without clearing the flag."],"tags":["karate","retry","interruption","threading"],"backgroundTag":"thread-interrupted","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"}