karatelabs/karate · error · RuntimeException
cache() second argument must be a function:
Error message
cache() second argument must be a function:
What it means
The second argument to HttpRequest.cache(key, fn) must be a JavaCallable (a function/l callable). If the value passed is not invokable (string, number, map, null), the library throws this error appended with the cache key to identify the offending call site.
Solutions
- Wrap the value in a function: request.cache('key', () => value)
- If you already have the value and just want to seed the cache, invoke it lazily anyway or write to the cache store directly
- Check that the referenced function name exists and is not shadowed by a variable holding data
- If calling from Java, pass a lambda/JavaCallable, not a raw Object
Example fix
// before
request.cache("token", token); // token is a string, throws
// after
request.cache("token", () => token); Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof fn !== 'function') throw new Error('cache() second argument must be a function for key: ' + key);
request.cache(key, fn); Type guard
function isCallable(v) { return v != null && (typeof v === 'function' || v instanceof Java.type('io.karatelabs.common.JavaCallable')); } Try / catch
try {
request.cache(key, maybeFn);
} catch (RuntimeException e) {
if (e.getMessage().startsWith("cache() second argument must be a function")) {
request.cache(key, function() { return maybeFn; }); // wrap the value lazily
} else { throw e; }
} Prevention
- Ensure the second argument is a lambda/function, not a value
- Check that function names are not shadowed by data variables
- In Java, pass a lambda (JavaCallable-compatible), never a raw Object
When it happens
Trigger: Calling cache('key', someValue) where someValue is a pre-computed value or a variable that is null/undefined instead of a lambda; passing a Java object that is not a JavaCallable; typos like cache('k', fnName) where fnName is undefined and coerced to a non-callable.
Common situations: Users confusing cache() semantics — expecting it to store an existing value directly — when it is a lazy get-or-compute API; dynamic scripts where a function reference was shadowed by data; cross-language bindings (JS vs Java) where lambdas do not convert to JavaCallable.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- cache() requires (key, fn)
- multipart fields expects a map:
- multipart files expects a list or map:
- multipart files entry must be a map:
- missing argument for multiPart()
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/148c0cbcdf014759.
Report an issue: GitHub.
Appendix: source
Thrown at karate-core/src/main/java/io/karatelabs/http/HttpRequest.java:762
* on this request, and returns the same value on subsequent calls. The
* store dies with the request — never crosses request boundaries.
* <p>
* The two-argument form is the only supported shape. If the key is
* missing, the second argument must be a function (otherwise a runtime
* error is raised). A cached {@code null} or {@code undefined} return
* value is still a cache hit and does not re-invoke the function.
*/
private JavaCallable cache() {
return (context, args) -> {
if (args.length < 2) {
throw new RuntimeException("cache() requires (key, fn)");
}
String key = args[0] + "";
if (cacheStore != null && cacheStore.containsKey(key)) {
return cacheStore.get(key);
}
if (!(args[1] instanceof JavaCallable fn)) {
throw new RuntimeException("cache() second argument must be a function: " + key);
}
Object value = fn.call(context);
if (cacheStore == null) {
cacheStore = new HashMap<>();
}
cacheStore.put(key, value);
return value;
};
}
@Override
public Object jsGet(String key) {
switch (key) {
case "method":
return method;
case "body":
return getBodyConverted();
case "bodyString":View on GitHub (pinned to a22eb90246)