{"record":{"id":"eb36bd7c217e4d61","repo":"karatelabs/karate","slug":"image-failed-to-read-options-optionspath-message","errorCode":null,"errorMessage":"image: failed to read options '{optionsPath}': {message}","messagePattern":"image: failed to read options '(.+?)': (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"karate-image/src/main/java/io/karatelabs/ext/image/ImageApi.java","lineNumber":384,"sourceCode":"    private String optionsDir() {\n        String dir = str(config.get(\"optionsDir\"));\n        return dir != null ? dir : str(config.get(\"baselineDir\"));\n    }\n\n    // ---- options file ----\n\n    private Map<String, Object> loadOptionsFile(String optionsPath) {\n        if (optionsPath == null) {\n            return new LinkedHashMap<>();\n        }\n        Resource r = resolveResource(optionsPath);\n        if (r == null || !r.exists()) {\n            return new LinkedHashMap<>();   // missing options is never an error\n        }\n        try (InputStream is = r.getStream()) {\n            return Json.of(new String(is.readAllBytes(), StandardCharsets.UTF_8)).asMap();\n        } catch (Exception e) {\n            throw new RuntimeException(\"image: failed to read options '\" + optionsPath + \"': \" + e.getMessage(), e);\n        }\n    }\n\n    /** Suite-level engine config passed to {@link ImageComparison} as defaultOptions. */\n    private Map<String, Object> defaultOptions() {\n        Map<String, Object> d = new LinkedHashMap<>();\n        d.put(\"engine\", config.getOrDefault(\"engine\", \"resemble\"));\n        if (config.containsKey(\"threshold\")) {\n            d.put(\"failureThreshold\", config.get(\"threshold\"));\n        }\n        d.put(\"report\", config.getOrDefault(\"report\", \"mismatched\"));\n        if (config.containsKey(\"allowScaling\")) {\n            d.put(\"allowScaling\", config.get(\"allowScaling\"));\n        }\n        if (config.containsKey(\"clusters\")) {\n            d.put(\"clusters\", config.get(\"clusters\"));\n        }\n        return d;","sourceCodeStart":366,"sourceCodeEnd":402,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-image/src/main/java/io/karatelabs/ext/image/ImageApi.java#L366-L402","documentation":"When diff() resolves a named baseline it loads the companion options JSON file. A missing options file is silently ignored, but if the file exists and cannot be read or parsed as JSON, loadOptionsFile wraps the failure in a RuntimeException naming the options path and underlying message.","triggerScenarios":"The <name>.options.json (or similarly resolved optionsPath) exists but contains invalid JSON, is unreadable due to permissions, or the stream fails mid-read while calling image.diff with a name.","commonSituations":"Hand-edited options file with a trailing comma or comments; options file saved with wrong encoding or as HTML (error page) by a misconfigured process; file locked or chmod'ed 000 in CI; partial file from an interrupted write.","solutions":["Open the optionsPath printed in the message and validate it is well-formed JSON (run it through a JSON linter)","Fix file permissions so the test process can read it","If the options are unnecessary, delete the file — a missing options file is treated as empty","Re-establish the baseline with image.write so a fresh, valid options file is written"],"exampleFix":"// before (options file, invalid)\n{ \"fuzzy\": 0.1, }\n// after\n{ \"fuzzy\": 0.1 }","handlingStrategy":"try-catch","validationCode":"# before calling image.diff, sanity-check the options file\n* def optsText = karate.readIfExists(optionsPath) || ''\n* if (optsText != '') eval \"JSON.parse(karate.string(optsText))\" // throws early on invalid JSON","typeGuard":null,"tryCatchPattern":"try { return karate.call('image.diff', { name: name }); } catch (Exception e) { if (('' + e).startsWith('image: failed to read options')) { karate.warn('bad options file, diffing with defaults'); return karate.call('image.diff', { name: name, optionsRemoved: true }); } throw e; }","preventionTips":["Validate options JSON files in CI (jq or a linter) before test runs","Never hand-edit generated options files without re-validating","Write options files atomically to avoid partial reads","Keep options files ASCII/UTF-8 without BOM or comments"],"tags":["karate","image-comparison","json","file-read"],"backgroundTag":"file-read-failed","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"}