karatelabs/karate · error · RuntimeException
karate.call() requires a feature context
Error message
karate.call() requires a feature context
What it means
executeJsCall implements karate.call() from JS, resolving a feature path (with optional tag selector and line filter) and invoking it against the current FeatureRuntime. A feature context is mandatory — the called feature runs as a child FeatureRuntime of the caller's. When featureRuntime is null, this RuntimeException is thrown.
Solutions
- Move the karate.call() usage into scenario or Background JS within a running feature.
- In karate-config.js, replace karate.call() with configure/variable assignment or use it only for pure JS helpers.
- If suite-level reuse is needed, call the feature at scenario level once and pass its results down instead of calling from callSingle JS.
- Ensure the caller feature is launched through Runner.path(...) so a FeatureRuntime exists.
Example fix
// before: inside karate.callSingle() JS
var result = karate.call('classpath:helpers/lookup.feature');
// after: inside a scenario
* def result = call read('classpath:helpers/lookup.feature') Defensive patterns
Strategy: type-guard
Type guard
// prefer the keyword inside features; reserve karate.call() for scenario JS
// * def result = call read('classpath:lookup.feature') { id: 1 } Try / catch
try {
var result = karate.call('classpath:lookup.feature', { id: 1 });
} catch (e) {
if (String(e).indexOf('requires a feature context') >= 0) {
karate.log('karate.call outside feature scope');
throw e; // structural misuse — do not swallow
}
throw e;
} Prevention
- Never call features from karate-config.js or callSingle JS
- Use the `call read(...)` keyword inside scenarios instead of karate.call()
- Keep feature-calling helpers scenario-scoped
- Run features through Runner so the FeatureRuntime exists
When it happens
Trigger: Calling karate.call('classpath:...') from JS that is not executing inside a feature — e.g. karate.callSingle() cached JS, karate-config.js evaluation, or a standalone script executed through the Karate JS engine outside a feature run.
Common situations: Wrapping feature calls in shared utility JS used by both callSingle and scenarios; calling features from karate-config.js during config init; using karate.call() in setup hooks that predate the feature runtime.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- karate.driver can only be read within a scenario
- karate.setup() is not available in this context
- karate.setup() requires a feature context
- karate.setupOnce() requires a feature context
- karate.call() arg must be a map or list, got
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/6c59c1171852095f.
Report an issue: GitHub.
Appendix: source
Thrown at karate-core/src/main/java/io/karatelabs/core/ScenarioRuntime.java:579
return new HashMap<>(result);
}
}
/**
* Execute a feature via karate.call() and return its result variables.
* This is used for JavaScript calls like: karate.call('other.feature', { arg: 'value' })
*
* Supports call-by-tag syntax:
* - call('file.feature@name=tagvalue') - call feature, run only scenario with matching tag
* - call('@tagname') - call scenario in same file by tag
*
* When arg is a List, loops over elements (same as `call read('path') array`) and
* returns a List of result maps.
*/
@SuppressWarnings("unchecked")
public Object executeJsCall(String path, Object arg) {
if (featureRuntime == null) {
throw new RuntimeException("karate.call() requires a feature context");
}
// Parse path, tag selector and line filter — shared parser keeps JS
// (karate.call) and keyword (`call read(...)`) syntax in lockstep.
StepUtils.ParsedFeaturePath parsed = StepUtils.parseFeaturePath(path);
String tagSelector = parsed.tagSelector();
Set<Integer> lineFilters = parsed.lineFilters();
Feature calledFeature;
if (parsed.sameFile()) {
// call('@tagname') — scenario in the same file
calledFeature = featureRuntime.getFeature();
} else {
Resource calledResource = featureRuntime.resolve(parsed.path());
// A .js target is a callable helper, not a feature — evaluate and invoke it,
// mirroring read()/callSingle and the `call` keyword (and v1, which dispatched
// on the resolved type). Blindly parsing it as a feature silently returned an
// empty result, dropping the helper's functions.
if ("js".equals(calledResource.getExtension())) {View on GitHub (pinned to a22eb90246)