skylot/jadx · error · RuntimeException
Failed to save JSON file: {}
Error message
Failed to save JSON file: {} What it means
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.
Source
Thrown at jadx-commons/jadx-analysis/src/main/java/jadx/analysis/callgraph/CallGraphExportDot.java:41
import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
import static java.nio.file.StandardOpenOption.WRITE;
public class CallGraphExportDot {
private final JadxArgs args;
private final ICallGraph callGraph;
public CallGraphExportDot(JadxArgs args, ICallGraph callGraph) {
this.args = args;
this.callGraph = callGraph;
}
public void writeTo(Path path) {
try {
FileUtils.makeDirsForFile(path);
Files.writeString(path, writeToString(), StandardCharsets.UTF_8,
WRITE, TRUNCATE_EXISTING, CREATE);
} catch (IOException e) {
throw new RuntimeException("Failed to save JSON file: " + path, e);
}
}
public String writeToString() {
// collect nodes
Map<Integer, Node> nodeMap = new HashMap<>();
for (ICallGraphEdge edge : callGraph.edges()) {
addNode(edge.from(), nodeMap);
addNode(edge.to(), nodeMap);
}
List<Node> nodes = new ArrayList<>(nodeMap.values());
nodes.sort(Comparator.comparingInt(o -> o.id));
SimpleCodeWriter cw = new SimpleCodeWriter(args);
cw.add("digraph CallGraph {");
for (Node node : nodes) {
cw.startLine();
addNodeName(cw, node.id);View on GitHub (pinned to e738a26571)
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.
Example fix
// before
exporter.writeTo(Path.of("/readonly/out.dot"));
// after
Files.createDirectories(Path.of("/tmp/cg"));
exporter.writeTo(Path.of("/tmp/cg/out.dot")); Defensive patterns
Strategy: validation
Validate before calling
Path parent = path.getParent();
if (parent == null || (!Files.exists(parent) && !parent.toFile().mkdirs())) {
throw new IllegalStateException("Cannot create output dir for: " + path);
}
if (!Files.isWritable(parent)) {
throw new IllegalStateException("Output dir not writable: " + parent);
} Type guard
public static boolean isOutputWritable(Path p) {
Path parent = p.getParent();
return parent != null && Files.isWritable(parent);
} Try / catch
try {
export.writeTo(path);
} catch (RuntimeException e) {
if (e.getMessage().startsWith("Failed to save JSON file")) {
LOG.error("Cannot write call-graph export to {}", path, e.getCause());
// retry to a temp location
export.writeTo(Files.createTempFile("callgraph", ".dot"));
} else throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Output directory not writable; disk full; path points to a location that needs elevated permissions; relative path resolved against an unexpected working directory.
Related errors
- Failed to save JSON file: {}
- Failed to init common directories
- Failed to create temp root directory
- {}
- Failed to open zip: {}
AI-assisted analysis of skylot/jadx@e738a26571 (2026-08-14).
Data as JSON: /api/errors/bd3f5870f3cf109c.
Report an issue: GitHub.