karatelabs/karate · error · RuntimeException

boot.read: file not found

Error message

boot.read: file not found: ${path} (root is ${root} — a leading '/' anchors the project root, 'file:' is a host path; declare boot.classpath(dir) to map 'classpath:' refs)

What it means

boot.read(path) attempted to resolve the path (e.g. a classpath: ref) and the underlying Resource resolution raised ResourceNotFoundException, which is converted into a RuntimeException explaining that the file was not found, what the root is, and that boot.classpath(dir) must be declared to map classpath: refs into a project directory. Unlike the plain not-found variant, this indicates resolution itself failed (typically a classpath: ref with no classpath root available).

Solutions

  1. Declare boot.classpath('src/test/resources') (or the correct dir) before the boot.read call.
  2. Put the resource on the real test classpath so classpath: resolution succeeds.
  3. Switch to a root-relative bare path or 'file:' path if the resource is not meant to be a classpath resource.
  4. Confirm the classpath dir mapping actually contains the file.

Example fix

// before
boot.read('classpath:mocks/certs.pem'); // ResourceNotFoundException
// after
boot.classpath('src/test/resources');
boot.read('classpath:mocks/certs.pem');
Defensive patterns

Strategy: validation

Validate before calling

// before reading a classpath: ref at boot
boot.classpath('src/test/resources'); // ensure mapping exists first
// and confirm the file is present in that dir

Try / catch

try {
    var text = boot.read('classpath:mocks/data.json');
} catch (RuntimeException e) {
    // fall back to a root-relative path or fail with a clear setup message
}

Prevention

When it happens

Trigger: boot.read('classpath:foo/bar.json') where the ref is not on the real classpath and boot.classpath(dir) was not declared (or classpathRoot resolution failed); a path that Resource.path cannot resolve to an existing location.

Common situations: Forgetting boot.classpath(...) before reading classpath: files kept only under src/test/resources; running in a context where the resource was never packaged into the jar; classpath dir mapping pointing at the wrong folder.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12). Data as JSON: /api/errors/45d392e6caaf7ddb. Report an issue: GitHub.

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/core/BootBinding.java:191

     * anchors THE project root, a bare ref is root-relative, {@code classpath:} is
     * classloader-first then the {@link #classpath(String)} fallback, and {@code file:} is a host
     * path. Declare {@code boot.classpath(...)} before reading a {@code classpath:} ref that is
     * not on the real classpath.
     */
    public String read(String path) {
        if (path == null) throw new IllegalArgumentException("boot.read: path is null");
        java.nio.file.Path classpathRoot = classpathDir == null || root == null
                ? root : root.resolve(classpathDir).normalize();
        try {
            Resource r = Resource.path(path, root, classpathRoot);
            if (r.exists()) {
                return r.getText();
            }
            throw new RuntimeException("boot.read: file not found: " + path
                    + " (resolved to " + r + "; root is " + root
                    + " — a leading '/' anchors the project root, 'file:' is a host path)");
        } catch (io.karatelabs.common.ResourceNotFoundException e) {
            throw new RuntimeException("boot.read: file not found: " + path
                    + " (root is " + root + " — a leading '/' anchors the project root, "
                    + "'file:' is a host path; declare boot.classpath(dir) to map 'classpath:' refs)", e);
        }
    }

    /** {@code boot.log('...')} — INFO log with [boot] prefix. */
    public void log(Object msg) {
        logger.info("[boot] {}", msg == null ? "null" : msg.toString());
    }

    /**
     * {@code boot.ext('name')} — resolve + construct + register an ext.
     *
     * <p>Resolution by name convention: {@code 'openapi'} →
     * {@code io.karatelabs.ext.openapi.OpenapiExt}. The class is loaded from
     * the runtime classloader; missing ext → boot-time failure (suite fails loud).</p>
     *
     * <p>Same name twice returns the same singleton instance.</p>

View on GitHub (pinned to a22eb90246)