karatelabs/karate · critical · RuntimeException
karate-boot.js evaluation failed
Error message
karate-boot.js evaluation failed: ${e.getMessage()} What it means
karate-boot.js is evaluated at suite startup via BootLoader.evalIfPresent, binding a 'boot' object into the JS engine. Any exception thrown while evaluating this bootstrap script is wrapped in a RuntimeException and re-thrown, making the failure fatal to the whole Suite per design decision K43 — the caller of Suite.run() sees it directly.
Solutions
- Read the wrapped exception's cause (the second argument) and fix the JS error at the reported line in karate-boot.js
- Temporarily remove/rename karate-boot.js from the classpath to confirm it is the source of the failure
- Update the boot script for the current Karate version's API surface (check docs/MIGRATION_GUIDE.md)
- Validate the script with a JS syntax checker or run it in a minimal engine harness before shipping it on the classpath
Example fix
// before (karate-boot.js)
var boot = karate.configure('report', { logLevel: 'INFO' });
// after
var boot = karate.configure('logging', { report: 'info' }); Defensive patterns
Strategy: try-catch
Validate before calling
// before running the suite, smoke-eval the boot script
try { new javax.script.ScriptEngineManager().getEngineByName('js').eval(bootJsSource); } catch (e) { throw new Error('karate-boot.js invalid: ' + e.message); } Type guard
// ensure the boot resource exists on the classpath before Suite.run
boolean bootPresent = getClass().getResource('/karate-boot.js') != null; Try / catch
try { Suite.run(suite); } catch (RuntimeException e) { if (e.getMessage().startsWith('karate-boot.js evaluation failed')) { log.error('Boot script broken, cause:', e.getCause()); } throw e; } Prevention
- Keep karate-boot.js minimal and version it with the test codebase
- Syntax-check the script in CI before packaging
- Re-validate the boot script after every Karate upgrade
When it happens
Trigger: karate-boot.js exists on the boot classpath/resource path but its evaluation throws — e.g. a JS syntax error in the script, a call to an API that doesn't exist in the embedded engine, or a user-supplied boot script that references missing variables or throws at top level.
Common situations: Teams customize karate-boot.js on the classpath to pre-load globals or polyfills; after a Karate version upgrade the old script references removed APIs; a typo or half-edited boot script is committed; the script depends on a resource that isn't packaged into the test jar.
Related errors
- Unable to resolve global `this`
- Invalid ignore
- boot.classpath: dir is null — pass a project-relative…
- boot.classpath(' '): expected a directory RELATIVE to the…
- boot.read: path is null
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/c3c16a043ce7edb3.
Report an issue: GitHub.
Appendix: source
Thrown at karate-core/src/main/java/io/karatelabs/core/BootLoader.java:89
public static BootBinding evalIfPresent(Suite suite, Path bootstrapWorkingDir, String env) {
Resource resource = locate(bootstrapWorkingDir);
if (resource == null) {
return null;
}
logger.info("{} processed", BOOT_FILE_NAME);
BootBinding boot = new BootBinding(suite, suite == null ? bootstrapWorkingDir : suite.getRoot(), env,
suite == null ? e -> {} : suite::registerExtListener);
Engine engine = new Engine();
// ExternalBridge enables reflective dispatch for plain Java methods on
// the bound objects — required for boot.ext(name) / boot.read(path) etc.
engine.setExternalBridge(new ExternalBridge() {});
engine.putRootBinding("boot", boot);
try {
engine.eval(resource);
} catch (Exception e) {
// Boot-time failure is fatal per K43 — re-throw as RuntimeException so
// Suite.run()'s caller sees it.
throw new RuntimeException(
"karate-boot.js evaluation failed: " + e.getMessage(), e);
}
return boot;
}
/**
* Boot-only evaluation: run {@code karate-boot.js} for a project working dir and return the
* {@link BootBinding} <b>without running any features</b> (no {@code SUITE_ENTER}/{@code SUITE_EXIT},
* no scenarios). The boot side effects — exts constructed + configured via {@code boot.ext(name)} +
* {@code .putMember(...)} during the JS eval — are the whole point, so a caller that lives outside a
* run (e.g. a persistent serve engine re-deriving a project's per-run {@code cov.*} config) can reach
* the booted, configured exts on demand.
*
* <p>Constructs the minimal {@link Suite} the boot phase needs (this package owns the package-private
* Suite construction, so callers don't have to) anchored at {@code workingDir}, and returns the
* binding the Suite constructor already evaluated. Returns {@code null} when {@code workingDir} is
* null or no {@code karate-boot.js} is present (the no-ext zero-cost path is preserved).</p>
*View on GitHub (pinned to a22eb90246)