{"record":{"id":"df328b211d08d957","repo":"karatelabs/karate","slug":"ext-onshutdown-failed","errorCode":null,"errorMessage":"ext onShutdown failed ({}): {}","messagePattern":"ext onShutdown failed \\((.+?)\\): (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"karate-core/src/main/java/io/karatelabs/core/Suite.java","lineNumber":613,"sourceCode":"            }\n\n            // Close JSONL event writer\n            if (jsonlWriter != null) {\n                try {\n                    removeJsonlListener(jsonlWriter);\n                    jsonlWriter.close();\n                } catch (Exception e) {\n                    logger.warn(\"Failed to close JSONL event stream: {}\", e.getMessage());\n                }\n            }\n\n            // Ext onShutdown — best-effort; exceptions are logged + dropped per K43.\n            if (bootBinding != null) {\n                for (Ext ext : bootBinding.getExts()) {\n                    try {\n                        ext.onShutdown();\n                    } catch (Exception e) {\n                        logger.warn(\"ext onShutdown failed ({}): {}\",\n                                ext.getClass().getName(), e.getMessage());\n                    }\n                    removeJsonlListener(ext);\n                }\n            }\n\n            // Notify listeners\n            for (ResultListener listener : resultListeners) {\n                listener.onSuiteEnd(result);\n            }\n        }\n\n        return result;\n    }\n\n    // Thread-safe listener management for JSONL writer\n    private final List<RunListener> mutableListeners = new ArrayList<>();\n","sourceCodeStart":595,"sourceCodeEnd":631,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-core/src/main/java/io/karatelabs/core/Suite.java#L595-L631","documentation":"Karate 'ext' boot extensions can register an onShutdown callback invoked when the Suite finishes. Each callback is best-effort: if one throws, Karate logs this warning naming the extension class and the exception message, then keeps going (the ext's JSONL listener registration is still removed). Suite results are unaffected.","triggerScenarios":"Suite.run() teardown iterating bootBinding.getExts() where ext.onShutdown() throws — e.g. a custom Ext whose onShutdown closes resources that are already closed, performs network cleanup that fails, or has a bug.","commonSituations":"Custom plugin/extension closing an HTTP client or DB pool twice; extension trying to flush data to a service that is unreachable at teardown; exceptions inside user-provided shutdown hooks.","solutions":["Fix the Ext.onShutdown() implementation named in the log to be idempotent and exception-safe","Wrap external cleanup in the extension with its own try/catch and meaningful logging","Make sure onShutdown only releases resources the extension itself created","If the extension is third-party, update it or remove it from the boot binding if not needed"],"exampleFix":"// before\n@Override public void onShutdown() { client.close(); files.flush(); }\n// after\n@Override public void onShutdown() {\n  try (client) { files.flushQuietly(); }\n  catch (Exception e) { logger.warn(\"ext cleanup failed\", e); }\n}","handlingStrategy":"try-catch","validationCode":"// in your Ext: make shutdown idempotent and testable before wiring into boot binding\n@Override public void onShutdown() {\n    if (closed.getAndSet(true)) return;\n    try { doCleanup(); } catch (Exception e) { logger.warn(\"cleanup failed\", e); }\n}","typeGuard":null,"tryCatchPattern":"try { ext.onShutdown(); }\ncatch (Exception e) { logger.warn(\"ext onShutdown failed: {}\", e.getMessage()); } // mirror Karate's own best-effort handling in the Ext","preventionTips":["Write Ext.onShutdown() to be idempotent (guard with a closed flag)","Never let shutdown-time network or remote calls throw out of onShutdown","Only release resources the extension created; don't close shared/global resources","Log the real exception inside the extension instead of relying on e.getMessage() alone"],"tags":["extension","shutdown","lifecycle"],"backgroundTag":"internal-invariant-violation","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"}