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

  1. Read the wrapped exception's cause (the second argument) and fix the JS error at the reported line in karate-boot.js
  2. Temporarily remove/rename karate-boot.js from the classpath to confirm it is the source of the failure
  3. Update the boot script for the current Karate version's API surface (check docs/MIGRATION_GUIDE.md)
  4. 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

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


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)