karatelabs/karate · error · RuntimeException
<cached exception message>
Error message
<cached exception message>
What it means
Karate caches the result of a `call single` expression. If the cached result is actually a CallSingleException (the call failed previously), unwrapCachedResult rethrows it as a RuntimeException wrapping the original cause, so every consumer of the cache sees the same failure instead of a result.
Solutions
- Fix the root cause shown in the chained `cause` (the original callSingle exception) and restart the JVM/test run to clear the cache
- Check the callSingle expression for idempotency and error handling; wrap risky logic so it returns a value instead of throwing
- Clear or key the cache differently (unique callSingle key per environment/inputs) so a poisoned entry is not reused
Example fix
// before: callSingle throws and poisons the cache
* def config = karate.callSingle('lookup.feature')
// after: make the callSingle resilient
* def config = karate.callSingle('function(){ try { return karate.call('lookup.feature'); } catch (e) { return { error: e.message } } })() Defensive patterns
Strategy: try-catch
Validate before calling
// cannot inspect the cache directly; make the callSingle expression defensive
function(){ try { return karate.call('lookup.feature'); } catch (e) { return { error: e.message }; } } Try / catch
try { result = karate.callSingle('lookup.feature'); } catch (RuntimeException e) { logger.error("cached callSingle failure", e.getCause()); throw e; } Prevention
- Make callSingle expressions idempotent and never throw (return error objects instead)
- Use unique callSingle keys per environment/inputs
- After fixing the root cause, restart the test JVM to clear the in-memory cache
When it happens
Trigger: Re-using a cached `call single` result when the original call had thrown: callSingle key maps to a CallSingleException and a subsequent callSingle with the same key reaches unwrapCachedResult.
Common situations: A `call single` block failed once (network blip, bad script) and remains in the in-memory cache; subsequent scenarios or retries re-throw the same cached error; users confused why the error persists after the underlying cause was fixed within the same JVM run.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- cache() requires (key, fn)
- cache() second argument must be a function:
- [callSingle] caching exception for
- [callSingle] disk cache read failed
- [callSingle] disk cache skipped
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/c4b08e2ce589d8be.
Report an issue: GitHub.
Appendix: source
Thrown at karate-core/src/main/java/io/karatelabs/core/ScenarioRuntime.java:951
String found = findNonJsonValue(list.get(i), path + "[" + i + "]", visited);
if (found != null) {
return found;
}
}
return null;
}
return path;
} finally {
visited.remove(value);
}
}
/**
* Unwrap cached result - throws if it's a cached exception.
*/
private Object unwrapCachedResult(Object cached) {
if (cached instanceof CallSingleException) {
throw new RuntimeException(((CallSingleException) cached).cause.getMessage(),
((CallSingleException) cached).cause);
}
return StepUtils.deepCopy(cached);
}
/**
* Wrapper for cached exceptions to distinguish from null results.
*/
private static class CallSingleException {
final Exception cause;
CallSingleException(Exception cause) {
this.cause = cause;
}
}
private void inheritVariables() {
boolean sharedScope = featureRuntime.isSharedScope();
// First check for callerScenario (the currently executing scenario that made the call)View on GitHub (pinned to a22eb90246)