karatelabs/karate · warning

hook failed

Error message

{} hook failed: {}

What it means

Karate runs lifecycle hooks (e.g. scenario setup/teardown callables) and, if a hook throws an Exception, logs this warning with the hook name and message and returns the exception to the caller instead of propagating it. The scenario continues unless the caller decides otherwise.

Solutions

  1. Read the hookName and message in the log to locate the failing hook
  2. Null-check any config/variables the hook reads
  3. Wrap risky parts of the hook body in try/catch inside the hook itself
  4. Run the hook's logic as a normal feature first to reproduce the error

Example fix

// before
configure afterScenario = function(){ karate.call('classpath:cleanup.feature') }
// after
configure afterScenario = function(){ try { karate.call('classpath:cleanup.feature') } catch(e){ karate.log('cleanup failed', e) } }
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate hook dependencies at config time:
if (!karate.get('cleanupUrl')) { throw new Error('cleanupUrl missing; hook would fail'); }

Try / catch

try { callable.call(null); } catch (Exception e) { logger.warn("{} hook failed: {}", hookName, e.getMessage()); }

Prevention

When it happens

Trigger: Any registered lifecycle hook callable (`callable.call(null)`) throws — e.g. a `configure userDefinedHook` / `afterScenario` style hook whose JS or Java lambda raises.

Common situations: Hooks calling karate features that fail; null dereferences on missing config values; environment teardown scripts that error (DB cleanup, API calls).

Related errors


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

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/core/ScenarioRuntime.java:2252

            channels = new ArrayList<>();
        }
        channels.add(channel);
    }

    /**
     * Invoke a lifecycle hook (beforeScenario / afterScenario) if it is a callable.
     * Returns null on success or no-op; returns the Throwable on failure.
     * Exceptions are always logged WARN (callers decide whether to surface as a scenario failure).
     */
    private Throwable invokeHook(Object hookRef, String hookName) {
        if (!(hookRef instanceof JavaCallable callable)) {
            return null;
        }
        try {
            callable.call(null);
            return null;
        } catch (Exception e) {
            logger.warn("{} hook failed: {}", hookName, e.getMessage());
            return e;
        }
    }

    /**
     * Run a lifecycle hook and append a synthetic StepResult describing the invocation
     * to the scenario's step list so it renders in the HTML report alongside regular
     * Gherkin steps. The synthetic step carries any karate.call() results produced inside
     * the hook (via the same buffer real steps use) plus the hook's log / embed output.
     * Returns null when there is no callable hook configured or the hook passed; returns
     * the Throwable so callers can apply the existing stop/continue semantics.
     */
    private Throwable invokeAndRecordHook(Object hookRef, String hookName) {
        if (!(hookRef instanceof JavaCallable)) {
            return null;
        }
        long startTime = System.currentTimeMillis();
        long startNanos = System.nanoTime();

View on GitHub (pinned to a22eb90246)