{"record":{"id":"295b8f0a1dfe9cfd","repo":"karatelabs/karate","slug":"onstepfailure-hook-threw-continuing","errorCode":null,"errorMessage":"onStepFailure hook threw, continuing: {}","messagePattern":"onStepFailure hook threw, continuing: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"karate-core/src/main/java/io/karatelabs/core/ScenarioRuntime.java","lineNumber":2037,"sourceCode":"            return true;\n        }\n    }\n\n    /**\n     * Invoke the {@code configure onStepFailure} hook with a single info-map\n     * argument. The map exposes failure metadata plus three JS-callable\n     * methods (embed / proceed / stop) bound to {@code sr} and {@code decision}.\n     */\n    private void invokeOnStepFailureHook(StepResult sr, FailureDecision decision) {\n        Object hookRef = config.getOnStepFailure();\n        if (!(hookRef instanceof JavaCallable callable)) {\n            return;\n        }\n        try {\n            Map<String, Object> info = buildStepFailureInfo(sr, decision);\n            callable.call(null, new Object[]{info});\n        } catch (Throwable t) {\n            logger.warn(\"onStepFailure hook threw, continuing: {}\", t.toString());\n        }\n    }\n\n    private Map<String, Object> buildStepFailureInfo(StepResult sr, FailureDecision decision) {\n        Map<String, Object> info = new LinkedHashMap<>();\n        Throwable err = sr.getError();\n        info.put(\"error\", err == null ? null : err.getMessage());\n        Step step = sr.getStep();\n        if (step != null) {\n            Map<String, Object> stepInfo = new LinkedHashMap<>();\n            stepInfo.put(\"line\", step.getLine());\n            stepInfo.put(\"text\", step.getText());\n            stepInfo.put(\"prefix\", step.getPrefix());\n            info.put(\"step\", stepInfo);\n        }\n        info.put(\"scenarioName\", scenario == null ? null : scenario.getName());\n        if (scenario != null && scenario.getFeature() != null) {\n            info.put(\"featureName\", scenario.getFeature().getName());","sourceCodeStart":2019,"sourceCodeEnd":2055,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-core/src/main/java/io/karatelabs/core/ScenarioRuntime.java#L2019-L2055","documentation":"Karate invokes the user-supplied `configure onStepFailure` hook with a map of failure info after each failed step. If the hook callable itself throws, Karate logs this warning and continues the scenario; the hook's exception never masks the original failure.","triggerScenarios":"A registered `onStepFailure` JS/Java callable throws — e.g. it dereferences missing fields, calls a failing API for alerting, or has a JS syntax/runtime error.","commonSituations":"Hook reads a field absent from the failure-info map; webhook/alerting call inside the hook fails; typos in hook JS.","solutions":["Read `t.toString()` in the log to find the error inside your hook","Make the hook defensive: null-check fields of the `info` map before use","Move side effects (alerting, logging) into try/catch inside the hook itself","Test the hook in isolation with a deliberately failing step"],"exampleFix":"// before\nconfigure onStepFailure = function(info){ karate.call('classpath:alert.feature', { id: info.scenarioId.id }) }\n// after\nconfigure onStepFailure = function(info){ try { karate.call('classpath:alert.feature', { id: info.scenarioId.id }) } catch(e) { karate.log('alert failed', e) } }","handlingStrategy":"try-catch","validationCode":"// Inside the hook, validate the info map before use:\nconfigure onStepFailure = function(info){ if (!info || !info.scenarioId) { karate.log('no failure info'); return; } /* ... */ }","typeGuard":"function hasScenarioId(info) { return info != null && info.scenarioId != null; }","tryCatchPattern":"try { callable.call(null, new Object[]{info}); } catch (Throwable t) { logger.warn(\"onStepFailure hook threw, continuing: {}\", t.toString()); }","preventionTips":["Null-check every field you read from the failure-info map","Keep side effects (webhooks) wrapped in their own try/catch","Unit-test hooks with a deliberately failing step"],"tags":["karate","hooks","onstepfailure"],"backgroundTag":"hook-execution-failed","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}