{"record":{"id":"bd3f5870f3cf109c","repo":"skylot/jadx","slug":"failed-to-save-json-file","errorCode":null,"errorMessage":"Failed to save JSON file: {}","messagePattern":"Failed to save JSON file: (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"jadx-commons/jadx-analysis/src/main/java/jadx/analysis/callgraph/CallGraphExportDot.java","lineNumber":41,"sourceCode":"import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;\nimport static java.nio.file.StandardOpenOption.WRITE;\n\npublic class CallGraphExportDot {\n\tprivate final JadxArgs args;\n\tprivate final ICallGraph callGraph;\n\n\tpublic CallGraphExportDot(JadxArgs args, ICallGraph callGraph) {\n\t\tthis.args = args;\n\t\tthis.callGraph = callGraph;\n\t}\n\n\tpublic void writeTo(Path path) {\n\t\ttry {\n\t\t\tFileUtils.makeDirsForFile(path);\n\t\t\tFiles.writeString(path, writeToString(), StandardCharsets.UTF_8,\n\t\t\t\t\tWRITE, TRUNCATE_EXISTING, CREATE);\n\t\t} catch (IOException e) {\n\t\t\tthrow new RuntimeException(\"Failed to save JSON file: \" + path, e);\n\t\t}\n\t}\n\n\tpublic String writeToString() {\n\t\t// collect nodes\n\t\tMap<Integer, Node> nodeMap = new HashMap<>();\n\t\tfor (ICallGraphEdge edge : callGraph.edges()) {\n\t\t\taddNode(edge.from(), nodeMap);\n\t\t\taddNode(edge.to(), nodeMap);\n\t\t}\n\t\tList<Node> nodes = new ArrayList<>(nodeMap.values());\n\t\tnodes.sort(Comparator.comparingInt(o -> o.id));\n\n\t\tSimpleCodeWriter cw = new SimpleCodeWriter(args);\n\t\tcw.add(\"digraph CallGraph {\");\n\t\tfor (Node node : nodes) {\n\t\t\tcw.startLine();\n\t\t\taddNodeName(cw, node.id);","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/skylot/jadx/blob/e738a26571d02919f01df40de93bc9a44dee4e18/jadx-commons/jadx-analysis/src/main/java/jadx/analysis/callgraph/CallGraphExportDot.java#L23-L59","documentation":"Thrown by CallGraphExportDot.writeTo(Path) as a plain RuntimeException wrapping an IOException raised while writing the call-graph DOT/JSON export to disk. writeTo makes parent dirs for the file, then writes the string with WRITE/TRUNCATE_EXISTING/CREATE.","triggerScenarios":"Calling CallGraphExportDot.writeTo(path) where path cannot be created or written: parent directory missing/non-creatable, permission denied, disk full, or the path is invalid. Note: the message says 'JSON file' even though this exporter writes DOT-format content.","commonSituations":"Output directory not writable; disk full; path points to a location that needs elevated permissions; relative path resolved against an unexpected working directory.","solutions":["Ensure the target directory exists and is writable.","Use an absolute path to avoid working-directory ambiguity.","Free disk space.","Check the wrapped IOException for the precise OS-level reason."],"exampleFix":"// before\nexporter.writeTo(Path.of(\"/readonly/out.dot\"));\n// after\nFiles.createDirectories(Path.of(\"/tmp/cg\"));\nexporter.writeTo(Path.of(\"/tmp/cg/out.dot\"));","handlingStrategy":"validation","validationCode":"Path parent = path.getParent();\nif (parent == null || (!Files.exists(parent) && !parent.toFile().mkdirs())) {\n    throw new IllegalStateException(\"Cannot create output dir for: \" + path);\n}\nif (!Files.isWritable(parent)) {\n    throw new IllegalStateException(\"Output dir not writable: \" + parent);\n}","typeGuard":"public static boolean isOutputWritable(Path p) {\n    Path parent = p.getParent();\n    return parent != null && Files.isWritable(parent);\n}","tryCatchPattern":"try {\n    export.writeTo(path);\n} catch (RuntimeException e) {\n    if (e.getMessage().startsWith(\"Failed to save JSON file\")) {\n        LOG.error(\"Cannot write call-graph export to {}\", path, e.getCause());\n        // retry to a temp location\n        export.writeTo(Files.createTempFile(\"callgraph\", \".dot\"));\n    } else throw e;\n}","preventionTips":["Create and verify the output directory before exporting.","Use absolute paths in scripts to avoid cwd ambiguity.","Note the message says 'JSON file' even for the DOT exporter — do not be misled."],"tags":["call-graph","io","export","jadx"],"backgroundTag":null,"analyzedSha":"e738a26571d02919f01df40de93bc9a44dee4e18","analyzedAt":"2026-08-14T00:10:24.238Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}