{"record":{"id":"d9ded41b69a454a2","repo":"karatelabs/karate","slug":"retry-failed-after-attempts","errorCode":null,"errorMessage":"retry failed after  attempts: ","messagePattern":"retry failed after  attempts: ","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"karate-core/src/main/java/io/karatelabs/core/StepExecutor.java","lineNumber":2334,"sourceCode":"        } else if (body instanceof Map || body instanceof List) {\n            responseType = \"json\";\n        } else if (body instanceof org.w3c.dom.Node) {\n            responseType = \"xml\";\n        } else {\n            responseType = \"string\";\n        }\n        runtime.setHiddenVariable(\"responseType\", responseType);\n    }\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","sourceCodeStart":2316,"sourceCodeEnd":2352,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-core/src/main/java/io/karatelabs/core/StepExecutor.java#L2316-L2352","documentation":"Karate's `retry until` mechanism re-executes a step (typically an HTTP call) until a condition is met. When the condition is still not satisfied after `maxRetries` attempts (configured via `configure retry = { count: N, interval: M }`), StepExecutor throws this RuntimeException naming the retry count and the `retry until` expression that kept failing.","triggerScenarios":"A step annotated with `retry until <expression>` was executed and the expression remained false for `maxRetries` consecutive evaluations, with the configured retry interval slept between each attempt.","commonSituations":"Waiting for an async job to finish but the backend is genuinely slow or stuck; wrong `retry until` expression that never becomes true (e.g. comparing `responseStatus == 200` when the endpoint always returns 202); retry count configured too low for the operation's latency; environment slowness in CI.","solutions":["Increase the retry count and/or interval in `configure retry = { count: 10, interval: 3000 }`.","Verify the `retry until` expression is actually the success condition you intend (print `response` between retries).","Check the target system/service logs to see why the expected condition never occurs.","If the operation is legitimately long-running, replace polling with a webhook/callback or an explicit status endpoint called in a loop with fail-fast logging."],"exampleFix":"// before\nconfigure retry = { count: 3, interval: 1000 }\nAnd retry until responseStatus == 200\n// after\nconfigure retry = { count: 10, interval: 5000 }\nAnd retry until responseStatus == 200 && response.status == 'DONE'","handlingStrategy":"retry","validationCode":"// Before running, sanity-check retry config and condition\n* def retryCfg = { count: 10, interval: 5000 }\n* configure retry = retryCfg\n* assert retryCfg.count > 0 && retryCfg.interval > 0","typeGuard":null,"tryCatchPattern":"// Runner-level\ntry {\n    karate.run(feature);\n} catch (RuntimeException e) {\n    if (e.getMessage().startsWith(\"retry failed after\")) {\n        // inspect the target system; treat as environment/condition failure\n    }\n    throw e;\n}","preventionTips":["Size retry count/interval against measured worst-case backend latency.","Log the polled value on each attempt so failures are diagnosable.","Ensure the retry until expression tests the real completion condition.","Add an explicit timeout budget so retries finish before outer suite timeouts."],"tags":["karate","retry","http","timeout"],"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"}