karatelabs/karate · warning

watch mode enabled but no watchable files found - features…

Error message

watch mode enabled but no watchable files found - features may be from classpath JARs

What it means

Watch mode was enabled on the mock server, but after scanning all supplied features, none resolved to local files, so the file watcher has nothing to monitor. Karate logs this warning and continues serving features, but no hot reload will ever occur.

Solutions

  1. Provide at least one feature from the local file system so the watcher has a file to monitor.
  2. Copy features to a working directory at startup (e.g. in Docker: COPY to /features) and load from there.
  3. Turn off watch mode since it cannot function in this deployment shape.
  4. Run from an exploded directory layout instead of a JAR during development.

Example fix

// before
MockServer.feature("classpath:mocks/*.feature").watch(true).build() // in fat JAR
// after
MockServer.feature(Paths.get("/app/features")).watch(true).build()
Defensive patterns

Strategy: validation

Validate before calling

boolean anyLocal = features.stream().anyMatch(f -> f.getResource().isLocalFile());
if (watch && !anyLocal) throw new IllegalStateException("watch enabled but no local-file features");

Prevention

When it happens

Trigger: Every Feature passed to the ReloadingHandler comes from a non-local resource (classpath JARs); watchedFiles map ends up empty at MockServer startup with watch enabled.

Common situations: Mock server launched inside a packaged JAR; all features referenced with classpath: prefixes that resolve inside dependencies; running in a container from a single fat JAR expecting live-reload.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/core/MockServer.java:400

            this.args = args;
            this.pathPrefix = pathPrefix;
            this.javaBridgeEnabled = javaBridgeEnabled;
            this.requestExpressionsEnabled = requestExpressionsEnabled;

            // Track file modification times for each feature
            for (Feature feature : features) {
                Resource resource = feature.getResource();
                if (resource.isLocalFile()) {
                    watchedFiles.put(resource, resource.getLastModified());
                    logger.debug("watching file: {} (modified: {})", resource.getRelativePath(), resource.getLastModified());
                } else {
                    logger.warn("watch mode: cannot watch non-file resource: {} (classpath resources in JARs are not watchable)",
                            resource.getRelativePath());
                }
            }

            if (watchedFiles.isEmpty()) {
                logger.warn("watch mode enabled but no watchable files found - features may be from classpath JARs");
            }

            // Initialize handler
            handler = new MockHandler(features, args, pathPrefix, javaBridgeEnabled, requestExpressionsEnabled);
        }

        MockHandler getHandler() {
            return handler;
        }

        @Override
        public HttpResponse apply(HttpRequest request) {
            // Check if any watched file has been modified
            boolean needsReload = false;
            for (Map.Entry<Resource, Long> entry : watchedFiles.entrySet()) {
                Resource resource = entry.getKey();
                long lastKnown = entry.getValue();
                long current = resource.getLastModified();

View on GitHub (pinned to a22eb90246)