{"record":{"id":"0e1115c5c5773b00","repo":"karatelabs/karate","slug":"retry-condition-evaluation-failed","errorCode":null,"errorMessage":"retry condition evaluation failed: {}","messagePattern":"retry condition evaluation failed: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"karate-core/src/main/java/io/karatelabs/core/StepExecutor.java","lineNumber":2382,"sourceCode":"                // Request skipped by listener\n                response = HttpResponse.skipped(request);\n            }\n\n            // Fire HTTP_EXIT event (always, even for skipped)\n            if (suite != null) {\n                suite.fireEvent(HttpRunEvent.exit(response.getRequest(), response, runtime));\n            }\n\n            // Set response variables so the condition can access them\n            setResponseVariables(response);\n\n            // Evaluate retry condition\n            boolean conditionMet;\n            try {\n                Object result = runtime.eval(retryUntil);\n                conditionMet = Boolean.TRUE.equals(result);\n            } catch (Exception e) {\n                logger.warn(\"retry condition evaluation failed: {}\", e.getMessage());\n                conditionMet = false;\n            }\n\n            if (conditionMet) {\n                if (retryCount > 0) {\n                    logger.debug(\"retry condition satisfied after {} attempts\", retryCount + 1);\n                }\n                return response;\n            } else {\n                logger.debug(\"retry condition not satisfied: {}\", retryUntil);\n            }\n\n            // Restore request state for next retry (http().invoke() resets it)\n            http().restoreFrom(httpCopy);\n\n            retryCount++;\n        }\n    }","sourceCodeStart":2364,"sourceCodeEnd":2400,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-core/src/main/java/io/karatelabs/core/StepExecutor.java#L2364-L2400","documentation":"Karate evaluates a @retry-until condition by evaluating an expression via the runtime script engine. If the expression fails to evaluate (syntax error, undefined variable, non-boolean result), Karate logs this warning, treats the condition as not met, and continues retrying instead of failing the step. The message interpolates only e.getMessage(), which can be unhelpfully terse (e.g. '{}').","triggerScenarios":"A scenario uses retry-until / configure retry with an expression that throws when evaluated: referencing an undefined variable, a syntax error, calling a method that throws, or the expression returning null/non-Boolean so TRUE.equals fails logically (though that path does not warn).","commonSituations":"Typo in a response-scoped variable before the first request runs; JSON path or JS syntax errors in the retry expression; a helper function not yet defined when retry starts; copy-pasted expressions from another dialect (e.g. Groovy/Python).","solutions":["Fix the retry expression so it evaluates to a JS boolean and only references variables that exist at evaluation time","Check the adjacent log line for e.getMessage(); reproduce the expression in a * print statement to see the actual engine error","Guard the expression against missing data, e.g. retry-until responseStatus == 200 && response.foo != undefined && response.foo == 'x'","If the condition should stop retries on error, implement a custom loop with * configure retry = ... or manual JS with karate.call for clearer diagnostics"],"exampleFix":"// before\n* configure retry = { count: 5, interval: 2000 }\n* get /items\n* retry until response.data.status == 'DONE'\n// after (guard against undefined so evaluation never throws)\n* configure retry = { count: 5, interval: 2000 }\n* get /items\n* retry until responseStatus == 200 && response.data && response.data.status == 'DONE'","handlingStrategy":"validation","validationCode":"// before relying on retry, smoke-test the expression in the same feature\n* def __retryOk =\n  \"\"\"\n  (function(){ try { return !! (response.data && response.data.status == 'DONE'); }\n                catch(e){ karate.log('retry expr error: ' + e); return false; } })()\n  \"\"\"","typeGuard":"function safeRetryExpr(fn){ try { return !!fn(); } catch (e) { karate.log('retry expr failed: ' + e); return false; } }","tryCatchPattern":null,"preventionTips":["Only reference variables guaranteed to exist before retry starts (responseStatus, response)","Guard nested fields with undefined checks in the retry expression","Keep retry expressions to plain JS booleans; avoid calls into helpers that can throw","Reproduce the expression with * print / karate.log to see engine errors directly"],"tags":["retry","javascript","evaluation"],"backgroundTag":"invalid-argument-value","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"}