karatelabs/karate · warning

hook failed

Error message

{} hook failed: {}

What it means

A lifecycle hook (before/after mock request hook) registered on the mock server threw an exception when invoked. Karate catches it, logs a warning, and by default converts it into a 500 response via hookErrorResponse so the mocked endpoint still answers. It indicates a bug or unexpected condition inside user-supplied hook code, not in Karate itself.

Solutions

  1. Read the second '{}' value in the log — e.getMessage() of the hook exception — and fix the bug in the hook code.
  2. Wrap the hook body in defensive null checks / try-catch so it never throws for edge-case requests.
  3. If the hook failure should be tolerated, make the hook catch its own exceptions and return a fallback response.
  4. Check that the hook returns/behaves correctly for all HTTP verbs and paths the mock receives.

Example fix

// before
fn = function(req){ return { status: req.body.length } }
// after
fn = function(req){ if (!req.body) return { status: 400 }; try { return { status: req.body.length } } catch (e) { return { status: 500, message: e.message } } }
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure hook is a function and deps exist before registering
if (typeof hookFn !== 'function') throw new Error('hook must be a function');

Type guard

function isValidHook(h) { return h && typeof h === 'function'; }

Try / catch

try { hook.call(null); } catch (e) { logger.warn('hook failed: {}', e.getMessage()); /* tolerate or return 500 via hookErrorResponse */ }

Prevention

When it happens

Trigger: A hook object passed to MockHandler (mock before/after hooks) throws when hook.call(null) is executed during request processing, via invokeMockHook called from beforeError/afterError handling.

Common situations: Hook script references a variable that does not exist; hook JS/Java code throws NPE; hook depends on request state that is absent for certain HTTP methods; a refactor renamed a variable the hook uses.

Related errors


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

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/core/MockHandler.java:531

        // A hook exception surfaces as HTTP 500 (same convention as beforeScenario / step failures).
        Exception afterError = invokeMockHook(config.getAfterScenario(), "afterScenario");
        if (afterError != null) {
            return hookErrorResponse("afterScenario", afterError);
        }

        // Build response from variables
        return buildResponse(runtime, engine, request);
    }

    private Exception invokeMockHook(JavaCallable hook, String hookName) {
        if (hook == null) {
            return null;
        }
        try {
            hook.call(null);
            return null;
        } catch (Exception e) {
            logger.warn("{} hook failed: {}", hookName, e.getMessage());
            return e;
        }
    }

    private HttpResponse hookErrorResponse(String hookName, Exception error) {
        return HttpResponse.error(500, hookName + " hook failed: " + error.getMessage());
    }

    @SuppressWarnings("unchecked")
    private HttpResponse buildResponse(ScenarioRuntime runtime, Engine engine, HttpRequest request) {
        HttpResponse response = new HttpResponse();

        // Get response variables from engine
        Object responseBody = engine.get("response");
        Object responseStatus = engine.get("responseStatus");
        Object responseStatusText = engine.get("responseStatusText");
        Object responseHeaders = engine.get("responseHeaders");
        Object responseDelay = engine.get("responseDelay");

View on GitHub (pinned to a22eb90246)