{"record":{"id":"4cf21dab92403856","repo":"karatelabs/karate","slug":"ext-name-resource-vanished-after-validation-path","errorCode":null,"errorMessage":"ext '<name>': resource vanished after validation: <path>","messagePattern":"ext '<name>': resource vanished after validation: <path>","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"karate-core/src/main/java/io/karatelabs/core/ReportAssets.java","lineNumber":211,"sourceCode":"        Files.createDirectories(extDir);\n        copyResource(js, extDir.resolve(stripStatic(js)));\n        if (css != null) {\n            copyResource(css, extDir.resolve(stripStatic(css)));\n        }\n        for (String a : assets) {\n            copyResource(a, extDir.resolve(stripStatic(a)));\n        }\n        for (Page p : pages) {\n            if (p.href() != null) {\n                copyResource(p.href(), extDir.resolve(p.href()));\n            }\n        }\n    }\n\n    private void copyResource(String path, Path target) throws IOException {\n        try (InputStream is = classLoader.getResourceAsStream(BASE + path)) {\n            if (is == null) {\n                throw new IOException(\"ext '\" + name + \"': resource vanished after validation: \" + path);\n            }\n            Path parent = target.getParent();\n            if (parent != null) {\n                Files.createDirectories(parent);\n            }\n            Files.copy(is, target, java.nio.file.StandardCopyOption.REPLACE_EXISTING);\n        }\n    }\n\n    private void requireResource(ClassLoader cl, String path, String key) {\n        try (InputStream is = cl.getResourceAsStream(BASE + path)) {\n            if (is == null) {\n                throw new RuntimeException(\"ext '\" + name + \"': \" + key\n                        + \" points at missing resource: \" + BASE + path);\n            }\n        } catch (IOException e) {\n            throw new RuntimeException(\"ext '\" + name + \"': failed reading \" + BASE + path + \" — \" + e.getMessage(), e);\n        }","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-core/src/main/java/io/karatelabs/core/ReportAssets.java#L193-L229","documentation":"During report generation, ReportAssets.copyResource finds that a classpath resource which passed earlier validation can no longer be opened. This is an IOException thrown mid-copy, indicating the classpath changed between validation and copy (or the resource was never addressable through this classloader).","triggerScenarios":"copyTo() copying a previously validated js/css/asset whose getResourceAsStream now returns null — e.g. jar rebuilt or classloader swapped between validateAndBind and report generation.","commonSituations":"Fat-jar shading that strips resources; the resource living in a different jar not on the runtime classpath; hot-reload/dev mode where target/classes was cleaned mid-run; module/classloader isolation (app server) hiding the resource from this ClassLoader.","solutions":["Re-run validateAndBind / restart the Suite after any rebuild so validation and copy use the same classpath","Confirm the resource exists in the built artifact: jar tf app.jar | grep <path>","Use the same ClassLoader for validation and copy (e.g. Thread.currentThread().getContextClassLoader())","Ensure build config (Maven/Gradle resources) includes the report assets directory"],"exampleFix":"// before (validate with one loader, copy with another)\nassets.validateAndBind(MyApp.class.getClassLoader());\n// after\nClassLoader cl = Thread.currentThread().getContextClassLoader();\nassets.validateAndBind(cl);\n// ... later, copyTo must use the same cl","handlingStrategy":"fallback","validationCode":"boolean present(ClassLoader cl, String path) { return cl.getResource(BASE + path) != null; }","typeGuard":null,"tryCatchPattern":"try { assets.copyTo(targetDir); } catch (IOException e) { if (e.getMessage().contains(\"resource vanished\")) { log.warn(\"classpath changed mid-run; revalidating\"); assets.validateAndBind(cl); assets.copyTo(targetDir); } else throw e; }","preventionTips":["Avoid rebuilding/cleaning the output directory while a suite is running","Use a single, stable ClassLoader for validation and copying","Verify resources survive into the packaged jar (shade plugin includes)"],"tags":["reporting","classpath","io","resources"],"backgroundTag":"resource-not-found","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"}