{"record":{"id":"53d39d4d63aaddd3","repo":"karatelabs/karate","slug":"proceed-can-only-be-called-within-a-mock-scenario","errorCode":null,"errorMessage":"proceed() can only be called within a mock scenario","messagePattern":"proceed\\(\\) can only be called within a mock scenario","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"karate-core/src/main/java/io/karatelabs/core/KarateJs.java","lineNumber":997,"sourceCode":"        };\n    }\n\n    /**\n     * karate.proceed() - Forward the current request to a target URL (proxy mode).\n     * Can only be used within a mock scenario.\n     * Usage:\n     * <pre>\n     * // Forward to specific target\n     * var response = karate.proceed('http://backend:8080');\n     *\n     * // Forward using Host header from request\n     * var response = karate.proceed();\n     * </pre>\n     */\n    private JavaInvokable proceed() {\n        return args -> {\n            if (mockHandler == null) {\n                throw new RuntimeException(\"proceed() can only be called within a mock scenario\");\n            }\n            HttpRequest currentRequest = mockHandler.getCurrentRequest();\n\n            String targetUrl;\n            if (args.length > 0 && args[0] != null) {\n                targetUrl = args[0].toString();\n            } else {\n                // Use Host header from request\n                String host = currentRequest.getHeader(\"Host\");\n                if (host == null) {\n                    throw new RuntimeException(\"proceed() needs a target URL or Host header in request\");\n                }\n                targetUrl = \"http://\" + host;\n            }\n\n            // Build request manually to avoid header conflicts\n            HttpRequestBuilder builder = new HttpRequestBuilder(client);\n            builder.url(targetUrl);","sourceCodeStart":979,"sourceCodeEnd":1015,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-core/src/main/java/io/karatelabs/core/KarateJs.java#L979-L1015","documentation":"karate.proceed() forwards the request currently being handled by a mock server to a real target URL (proxy mode). It only makes sense while a mock scenario is executing a request, because Karate needs the in-flight HttpRequest. Karate throws this error when mockHandler is null — i.e. proceed() was called from a scenario/test where no mock server handler is active.","triggerScenarios":"Calling karate.proceed() (with or without a URL argument) inside: a normal API test scenario (not a mock), a karate.callSingle setup, an @beforeall/@afterall hook, or a mock feature that runs outside the MockServer request-handling path.","commonSituations":"Copy-pasting a proceed() snippet from a mock-proxy example into a regular test feature; calling proceed() in a background section of a regular feature; running the same feature both as a test and as a mock without guarding the call.","solutions":["Only call karate.proceed() inside a scenario that is executed by a MockServer (the feature passed to karate.start({...mock:...}) or MockServer.feature(...))","In a regular test, replace proceed() with a direct HTTP call: karate.call('other.feature') or use the http client to hit the real backend","If the feature doubles as test and mock, guard the call: if (karate.proceed != null) { ... } or restructure into two features","Verify you are not calling proceed() from setup/teardown hooks where no request is in flight"],"exampleFix":"// before (regular test feature)\nWhen method get\nThen karate.proceed() // fails: no mock handler active\n\n// after (mock feature used via karate.start({mock: 'proxy.feature'}))\n* def response = karate.proceed('http://backend:8080')","handlingStrategy":"try-catch","validationCode":"// Only call proceed in features launched via karate.start({mock: ...}) or MockServer.feature(...).\n// Structure check: the file calling proceed() should be the mock feature, not a test feature.\n// No pre-call API exists to check mockHandler; keep mock features separate from test features.","typeGuard":null,"tryCatchPattern":"try {\n  var response = karate.proceed('http://backend:8080');\n} catch (e) {\n  if (('' + e).indexOf('can only be called within a mock scenario') !== -1) {\n    karate.log('proceed() called outside a mock handler — falling back to direct call');\n  }\n  throw e;\n}","preventionTips":["Keep proxy/mock features (that call proceed()) strictly separate from regular test features","Never call proceed() from background sections, callSingle, or hooks","Document in the mock feature header that it only runs under MockServer","If one feature serves both roles, branch on a flag set by the caller instead of assuming proceed() exists"],"tags":["javascript","mock-server","invalid-state","karate"],"backgroundTag":"invalid-state-transition","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-16T19:17:19.609Z"}