skylot/jadx · error · JadxRuntimeException
Ordering pass not found: {}, listed in 'runAfter' of pass: {
Error message
Ordering pass not found: {}, listed in 'runAfter' of pass: {}
all passes: {} What it means
Thrown by jadx's PassMerge when merging a custom JadxPass (from a plugin or registered pass) whose JadxPassInfo.runAfter() names a pass that is neither a built-in visitor nor a known merge pass. The message lists the offending name, the pass that declared it, and the full visitor-name list so you can compare. PassMerge computes an insertion position by looking up every name in runAfter against the current visitor order; an unresolved name is fatal because the ordering cannot be satisfied.
Source
Thrown at jadx-core/src/main/java/jadx/core/utils/PassMerge.java:80
if (ListUtils.isSingleElement(runBefore, JadxPassInfo.END)) {
return -1;
}
int visitorsCount = visitors.size();
Map<String, Integer> namePosMap = new HashMap<>(visitorsCount);
for (int i = 0; i < visitorsCount; i++) {
namePosMap.put(namesMap.get(visitors.get(i)), i);
}
int after = -1;
for (String name : runAfter) {
Integer pos = namePosMap.get(name);
if (pos != null) {
after = Math.max(after, pos);
} else {
if (mergePassesNames.contains(name)) {
// ignore known passes
continue;
}
throw new JadxRuntimeException("Ordering pass not found: " + name
+ ", listed in 'runAfter' of pass: " + pass
+ "\n all passes: " + ListUtils.map(visitors, namesMap::get));
}
}
int before = Integer.MAX_VALUE;
for (String name : runBefore) {
Integer pos = namePosMap.get(name);
if (pos != null) {
before = Math.min(before, pos);
} else {
if (mergePassesNames.contains(name)) {
// ignore known passes
continue;
}
throw new JadxRuntimeException("Ordering pass not found: " + name
+ ", listed in 'runBefore' of pass: " + pass
+ "\n all passes: " + ListUtils.map(visitors, namesMap::get));
}View on GitHub (pinned to e738a26571)
Solutions
- Read the 'all passes:' list in the message and correct the runAfter() name in your JadxPassInfo to exactly match a built-in pass name.
- Verify your plugin's jadx-api dependency version matches the running jadx build (a renamed/removed pass indicates a version skew).
- If the referenced pass is another custom pass, ensure that pass's plugin is actually loaded before yours (check plugin load logs) so it appears in mergePassesNames.
- Drop the runAfter() constraint for that name if you only need loose ordering, or use JadxPassInfo.START to run first.
Example fix
// before
public JadxPassInfo getInfo() {
return new JadxPassInfo("my-pass", "my pass")
.runAfter("ModVisitor"); // typo / removed name -> error
}
// after
public JadxPassInfo getInfo() {
return new JadxPassInfo("my-pass", "my pass")
.runAfter("MethodInvokeVisitor"); // exact built-in name
} Defensive patterns
Strategy: validation
Validate before calling
// Validate runAfter names against the live visitor pass list before registering.
Set<String> known = visitors.stream().map(IDexTreeVisitor::getName).collect(Collectors.toSet());
for (String n : passInfo.runAfter()) {
if (!known.contains(n) && !mergePassNames.contains(n)
&& !JadxPassInfo.START.equals(n) && !JadxPassInfo.END.equals(n)) {
throw new IllegalArgumentException("runAfter references unknown pass: " + n
+ ". Known: " + known);
}
} Try / catch
// Wrap pass registration so a bad ordering hint fails fast with context.
try {
passMerge.merge(customPasses, wrapFn);
} catch (JadxRuntimeException e) {
LOG.error("Pass merge failed (check runAfter names/version): {}", e.getMessage());
throw e;
} Prevention
- Pin your plugin's jadx-api version to the exact jadx build you target.
- Copy built-in pass names from the jadx source rather than typing them.
- When upgrading jadx, diff the built-in pass list for renames/removals.
- Prefer JadxPassInfo.START/END sentinels over naming specific passes when possible.
When it happens
Trigger: Registering a plugin JadxPass whose info().runAfter("foo") references a pass name that does not exist among built-in IDexTreeVisitor passes and is not itself a registered merge pass. Happens in PassMerge.merge() -> searchInsertPos() at the runAfter loop when namePosMap.get(name)==null and mergePassesNames.contains(name)==false.
Common situations: Plugin/jadx version mismatch where a pass was renamed or removed in a newer jadx (e.g. a pass renamed across a major release); a typo in the pass name string in runAfter(); a custom pass that declares a dependency on another custom pass that was never registered because its plugin failed to load.
Related errors
- Ordering pass not found: {}, listed in 'runBefore' of pass:
- Conflict order requirements for pass: {} run after: {} run
- Duplicate plugin id: {}, class {}
- Unknown type of resource file: ${resFile.getOriginalName()}
- Null option descriptions in plugin id: {}
AI-assisted analysis of skylot/jadx@e738a26571 (2026-08-14).
Data as JSON: /api/errors/b6cd61affc4bf08d.
Report an issue: GitHub.