karatelabs/karate · error · RuntimeException

boot.ext(' '): failed to construct

Error message

boot.ext('${name}'): failed to construct ${className} — ${e.getMessage()}

What it means

boot.ext(name) found and loaded the Ext class but instantiating it (via getDeclaredConstructor().newInstance()) failed — for reasons other than the class being missing — such as a missing no-arg constructor, a constructor that threw, or security/reflective access failure. The RuntimeException wraps the cause and reports the original message.

Solutions

  1. Give the Ext class a public no-argument constructor and move initialization work into onBoot(suite) instead of the constructor.
  2. Make the class public and non-abstract.
  3. Read the wrapped cause (e.getMessage() in the message) and fix whatever the constructor is doing that throws.
  4. Guard constructor-time environment dependencies so construction succeeds in any environment.

Example fix

// before
public class MyExt implements Ext {
    public MyExt(String configPath) { ... } // no no-arg ctor
}
// after
public class MyExt implements Ext {
    public MyExt() { }
    public void onBoot(Suite suite) { /* init here */ }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// verify the Ext class can be constructed before boot
Ext.class.cast(cls.getDeclaredConstructor().newInstance()); // mirrors library behavior

Try / catch

try {
    boot.ext(name);
} catch (RuntimeException e) {
    Throwable cause = e.getCause();
    // cause reveals constructor failure: missing no-arg ctor, thrown init exception, access flags
}

Prevention

When it happens

Trigger: The resolved Ext class has no accessible no-arg constructor; the constructor throws an exception during initialization (e.g. it reads config files or connects to services at construction time and fails); InstantiationException for abstract classes; IllegalAccessException for non-public classes.

Common situations: Extension written with a required-argument constructor; constructor performing eager I/O that fails in CI environments; class declared abstract by mistake; extension class not public.

Related errors


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

Appendix: source

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

            }
        }
        String className = extClassName(name);
        Ext ext;
        try {
            Class<?> cls = Class.forName(className);
            Object instance = cls.getDeclaredConstructor().newInstance();
            if (!(instance instanceof Ext)) {
                throw new RuntimeException(
                        "boot.ext('" + name + "'): " + className
                                + " does not implement io.karatelabs.core.Ext");
            }
            ext = (Ext) instance;
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(
                    "boot.ext('" + name + "'): not on classpath. Expected "
                            + className + " (name-convention resolution).", e);
        } catch (Exception e) {
            throw new RuntimeException(
                    "boot.ext('" + name + "'): failed to construct " + className
                            + " — " + e.getMessage(), e);
        }
        // Fire onBoot eagerly per K43. Throws here fail the Suite.
        ext.onBoot(suite);
        exts.add(ext);
        registrar.accept(ext);
        logger.info("ext booted: {} ({})", name, ext.getClass().getName());
        return ext;
    }

    /**
     * {@code boot.has('name')} — is this ext available to boot? A pure classpath probe using the same
     * name convention as {@link #ext(String)}; constructs nothing and registers nothing.
     *
     * <p>Exists because {@code boot.ext} is deliberately strict — a typo, or a missing ext the project
     * genuinely depends on, must fail the suite loudly. But a project may legitimately depend on an ext
     * <i>only when it is present</i>: a kit whose gRPC/Kafka beat is optional still has to run on a

View on GitHub (pinned to a22eb90246)