skylot/jadx · error · JadxRuntimeException

No loaded files

Error message

No loaded files

What it means

Thrown by JadxDecompiler.getSaveTasks() when the internal root RootNode is null, meaning load() was never successfully called (or failed) before save() was invoked. Save requires the loaded class/resource tree, so without it there is nothing to write. It is a JadxRuntimeException (unchecked) with the literal message 'No loaded files'.

Source

Thrown at jadx-core/src/main/java/jadx/api/JadxDecompiler.java:308

	public ITaskExecutor getSaveTaskExecutor() {
		return getSaveTasks(!args.isSkipSources(), !args.isSkipResources());
	}

	@Deprecated(forRemoval = true)
	public ExecutorService getSaveExecutor() {
		ITaskExecutor executor = getSaveTaskExecutor();
		executor.execute();
		return executor.getInternalExecutor();
	}

	@Deprecated(forRemoval = true)
	public List<Runnable> getSaveTasks() {
		return Collections.singletonList(this::save);
	}

	private TaskExecutor getSaveTasks(boolean saveSources, boolean saveResources) {
		if (root == null) {
			throw new JadxRuntimeException("No loaded files");
		}
		OutDirs outDirs;
		ExportGradle gradleExport;
		if (args.getExportGradleType() != null) {
			gradleExport = new ExportGradle(root, args.getOutDir(), getResources());
			outDirs = gradleExport.init();
		} else {
			gradleExport = null;
			outDirs = new OutDirs(args.getOutDirSrc(), args.getOutDirRes());
			outDirs.makeDirs();
		}

		TaskExecutor executor = new TaskExecutor();
		executor.setThreadsCount(args.getThreadsCount());
		if (saveResources) {
			// save resources first because decompilation can stop or fail
			appendResourcesSaveTasks(executor, outDirs.getResOutDir());
		}

View on GitHub (pinned to e738a26571)

Solutions

  1. Always call decompiler.load() and ensure it completes without exception before calling save().
  2. Check decompiler.getRoot() == null (or getClasses().isEmpty()) before saving to guard the call.
  3. If load() failed, diagnose and fix that first; saving is impossible without loaded files.
  4. Structure your wrapper so load and save cannot be called out of order.

Example fix

// before
JadxDecompiler d = new JadxDecompiler(args);
d.save(); // root is null

// after
JadxDecompiler d = new JadxDecompiler(args);
d.load();
if (d.getClasses().isEmpty()) {
    throw new IllegalStateException("load() produced no classes, nothing to save");
}
d.save();
Defensive patterns

Strategy: validation

Validate before calling

// Ensure load() ran successfully before saving.
if (decompiler.getClasses() == null || decompiler.getClasses().isEmpty()) {
    throw new IllegalStateException("No classes loaded; call load() first.");
}
decompiler.save();

Try / catch

try {
    decompiler.save();
} catch (JadxRuntimeException e) {
    if ("No loaded files".equals(e.getMessage())) {
        LOG.error("load() was not called or failed; cannot save.");
    } else throw e;
}

Prevention

When it happens

Trigger: Calling decompiler.save() or decompiler.getSaveTasks() without first calling (and completing) decompiler.load(), or calling save after a load() that threw and left root unpopulated.

Common situations: Programmatic integration that skips load(); a load() failure that was swallowed/ignored before save(); reordered initialization in a custom wrapper; unit tests that build a JadxDecompiler and jump straight to save.

Related errors


AI-assisted analysis of skylot/jadx@e738a26571 (2026-08-14). Data as JSON: /api/errors/6482c1dfb1275022. Report an issue: GitHub.