karatelabs/karate · error · RuntimeException
channel() can only be called within a scenario
Error message
channel() can only be called within a scenario
What it means
Channels are scenario-scoped: karate.channel(type) resolves the ChannelFactory via the current ScenarioRuntime's Suite. When no runtime is active (boot scripts, afterSuite, pure JS eval outside a scenario) the call cannot proceed and throws this error.
Solutions
- Call karate.channel() only inside a running scenario step or scenario-scoped JS
- Move channel setup into the scenario (or Background) rather than suite/boot hooks
- If using the embedded engine, ensure a scenario runtime exists before resolving channels.
Example fix
// before (afterSuite JS)
karate.channel('kafka').close();
// after — close inside the scenario
Scenario: teardown
* def ch = karate.channel('kafka')
* ch.close() Defensive patterns
Strategy: try-catch
Validate before calling
// JS: only call channel() inside scenario scope; guard shared helpers
function channelInScenario(type) { try { return karate.channel(type); } catch (e) { return null; } } Try / catch
try { var ch = karate.channel('kafka'); } catch (e) { if (String(e).indexOf('within a scenario') >= 0) karate.warn('move channel() into a scenario'); throw e; } Prevention
- Use karate.channel() only in scenario steps/scenario-scoped JS
- Do channel setup/teardown in scenarios, not suite or boot hooks
- For embedded engine use, ensure a scenario runtime exists first
When it happens
Trigger: Calling karate.channel('kafka') in karate-config.js, a call-single JS file executed outside a scenario, @AfterSuite hook, or any JS context where getRuntime() returns null.
Common situations: Utility scripts shared between scenario and boot contexts; setting up a channel listener in a suite hook instead of a scenario; calling channel() from a JVM-embedded Karate engine without running a feature scenario.
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
- channel() needs a type argument, e.g…
- karate.setup() is not available in this context
- setTimeout: karate is shutting down
- Unable to resolve global `this`
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/fff5931c997e2ca1.
Report an issue: GitHub.
Appendix: source
Thrown at karate-core/src/main/java/io/karatelabs/core/KarateJs.java:1203
private io.karatelabs.driver.Driver getDriverLazy() {
ScenarioRuntime rt = getRuntime();
if (rt == null) {
throw new RuntimeException("karate.driver can only be read within a scenario");
}
return rt.getDriver();
}
// ========== Channel Support ==========
private JavaInvokable channel() {
return args -> {
if (args.length == 0) {
throw new RuntimeException("channel() needs a type argument, e.g. karate.channel('kafka')");
}
String type = args[0].toString();
ScenarioRuntime rt = getRuntime();
if (rt == null) {
throw new RuntimeException("channel() can only be called within a scenario");
}
// An ext (e.g. boot.ext('grpc')) may have registered a factory on the Suite at boot;
// it wins over the name-convention fallback. See Suite#registerChannelFactory.
FeatureRuntime fr = rt.getFeatureRuntime();
Suite suite = fr != null ? fr.getSuite() : null;
ChannelFactory factory = suite != null ? suite.getChannelFactory(type) : null;
try {
if (factory == null) {
// No ext registered a factory for this type — resolve by name convention,
// mirroring boot.ext: channel('grpc') -> io.karatelabs.ext.grpc.GrpcChannelFactory.
String cap = Character.toUpperCase(type.charAt(0)) + type.substring(1);
String factoryClass = "io.karatelabs.ext." + type + "." + cap + "ChannelFactory";
Class<?> clazz = Class.forName(factoryClass);
factory = (ChannelFactory) clazz.getDeclaredConstructor().newInstance();
}
// Channels self-configure via their rich JS object, not via global config.
Channel channel = factory.create(rt, new HashMap<>());
rt.registerChannel(channel);View on GitHub (pinned to a22eb90246)