karatelabs/karate · error · RuntimeException
callSingle failed
Error message
callSingle failed: <path> - <failureMsg>
What it means
When karate.callSingle() invokes a feature and that child FeatureRuntime fails, executeCallSingle collects the first failed ScenarioResult's failure message and throws a RuntimeException 'callSingle failed: <path> - <message>'. This re-throws the underlying feature failure to the caller (and caches the exception for subsequent callSingle invocations of the same path).
Solutions
- Run the called feature standalone (Runner.path) to see the full failure and fix the root cause shown after the ' - '.
- Check environment/config the shared feature depends on (URLs, credentials) — callSingle features often fail before any test logic runs.
- Note the exception is cached: fix the feature and restart the suite; retrying within the same run returns the cached failure.
- If only JS is needed, prefer a .js file over a feature for callSingle to avoid full scenario execution overhead.
Example fix
// before: auth.feature fails
* def token = karate.callSingle('classpath:auth.feature').token
// -> callSingle failed: classpath:auth.feature - http call failed ...
// after: harden the shared feature
* configure retry = { count: 3, interval: 2000 }
* def token = karate.call('classpath:auth.feature').token Defensive patterns
Strategy: try-catch
Validate before calling
// validate the shared feature in a pre-flight check at suite start:
// Runner.path("classpath:auth.feature").parallel(1) in a build step before the suite Try / catch
try {
var token = karate.callSingle('classpath:auth.feature').token;
} catch (e) {
if (String(e).indexOf('callSingle failed') >= 0) {
karate.log('shared feature failed; cause: ' + e);
throw e; // usually a genuine env/config failure — don't mask
}
throw e;
} Prevention
- Keep callSingle feature scripts dependency-light (no env surprises)
- Add retry/configure timeouts in shared auth/data features
- Smoke-test shared features standalone before the full suite
- Remember the failure is cached per suite run — restart after fixing the feature
When it happens
Trigger: karate.callSingle('some.feature') where the called feature has a failing scenario — a failed step, assertion, or setup error. The reported message is the first failed scenario's failure text.
Common situations: Shared data-provision features (auth token fetch, seed data) failing due to environment issues; a broken helper feature reused across the suite so every callSingle consumer fails; parallel runs surfacing the cached exception repeatedly.
Related errors
- [callSingle] caching exception for
- karate.callSingle() is not available in this context
- karate.callSingle() requires at least one argument (path)
- karate.setupOnce() requires a feature context
- karate.callonce() requires a feature context
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/2067776d7db2087e.
Report an issue: GitHub.
Appendix: source
Thrown at karate-core/src/main/java/io/karatelabs/core/ScenarioRuntime.java:854
);
FeatureResult fr = nestedFr.call();
// Attach the called feature's result so its steps (and HTTP traffic) surface
// in the calling scenario's HTML / Cucumber JSON / JUnit report. callSingle
// executes exactly once per Suite under a lock — only the "winning" scenario
// (cache miss) reaches this code, so the call results appear under whichever
// scenario's thread actually ran the feature. Done before the failure throw
// so a failed callSingle still surfaces its steps in the report.
executor.addCallResult(fr);
// Check if the feature failed
if (fr.isFailed()) {
String failureMsg = fr.getScenarioResults().stream()
.filter(ScenarioResult::isFailed)
.findFirst()
.map(ScenarioResult::getFailureMessage)
.orElse("callSingle feature failed");
throw new RuntimeException("callSingle failed: " + path + " - " + failureMsg);
}
if (nestedFr.getLastExecuted() != null) {
// Cache only the delta — the variables the called feature actually added or
// replaced — not its full binding set. A called feature inherits the caller's
// visible variables, so the full set echoes back caller state: Scenario Outline
// example-row columns (frozen to row 1 and replayed onto later rows via a
// karate.set(...) spread — #2934) and config-level refs like Java.type(...)
// (serialized into the disk cache, then deserialized as broken values that
// clobber the live ref on a warm run — #2933). Diffed against what the callee
// was actually seeded with (isolated scope shallow-copies maps and lists, so
// comparing against the caller's own live vars read every inherited map as
// "replaced" and leaked it back) — the same helper the call keyword uses.
return StepExecutor.calleeResult(nestedFr.getLastExecuted());
}
return new HashMap<>();
} else if (content instanceof JavaCallable) {
// JavaScript function - invoke it with the argView on GitHub (pinned to a22eb90246)