pxb1988/dex2jar · error · RuntimeException

Can't merge and

Error message

Can't merge ${a} and ${b}

What it means

TypeClass represents value-type abstractions (zero/one/boolean, int/float, long, etc.) in dex2jar's IR. merge0 computes the least upper bound of two type classes; if either operand is JD (the 'double' class, which cannot combine with any other), no sensible result exists and the library throws this RuntimeException. It signals that the type-inference pass encountered two conflicting type sets during local variable merging.

Solutions

  1. Inspect the IrMethod locals and fix the pass that assigned double (JD) to a register used as another type
  2. Re-run on non-obfuscated DEX to confirm the input is the cause; preprocess with a dex deobfuscator
  3. If intentional, extend merge0's table or catch RuntimeException around the transform pipeline
  4. Report the input DEX as a dex2jar translation bug with the failing method

Example fix

// before (library)
if (a == JD || b == JD) {
    throw new RuntimeException("Can't merge " + a + " and " + b);
}
// after (caller guard)
TypeClass m;
try { m = TypeClass.merge(a, b); }
catch (RuntimeException e) { m = TypeClass.UNKNOWN; }
Defensive patterns

Strategy: try-catch

Validate before calling

if (a == TypeClass.JD || b == TypeClass.JD) {
    throw new IllegalArgumentException("cannot merge double class with " + a + "/" + b);
}
TypeClass merged = TypeClass.merge(a, b);

Type guard

boolean mergeable(TypeClass t) { return t != TypeClass.JD; }

Try / catch

try {
    merged = TypeClass.merge(a, b);
} catch (RuntimeException e) {
    if (!e.getMessage().startsWith("Can't merge ")) throw e;
    merged = TypeClass.UNKNOWN; // or re-run with corrected types
}

Prevention

When it happens

Trigger: Calling TypeClass.merge (or merge0 directly) with one argument being TypeClass.JD while the other is any type class that yields no entry in the merge table (e.g. merging a double-typed value with an int/float/object value).

Common situations: Deobfuscating or translating malicious/obfuscated DEX where the same register is written with a double in one branch and a different type in another; bugs in custom transformers that assign types inconsistently before Cfg/type analysis.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of pxb1988/dex2jar@b5bda4fb49 (2026-09-08). Data as JSON: /api/errors/6af5ae839ab10c3d. Report an issue: GitHub.

Appendix: source

Thrown at dex-ir/src/main/java/com/googlecode/dex2jar/ir/TypeClass.java:126

            } else if (clz.fixed) {
                return clz;
            } else { // both not fixed
                return merge0(thizCls, clz);
            }
        }
    }

    /**
     * X     ZIL   ZIFL ZIF  ZI  IF
     * ZIL   X     ZIL  ZI   ZI  I
     * ZIFL  ZIL   X    ZIF  ZI  IF
     * ZIF   ZI    ZIF  X    ZI  IF
     * ZI    ZI    ZI   ZI   X   I
     * IF    I     IF   IF   I   X
     */
    private static TypeClass merge0(TypeClass a, TypeClass b) {
        if (a == JD || b == JD) {
            throw new RuntimeException("Can't merge " + a + " and " + b);
        }
        switch (a) {
            case ZIL:
                switch (b) {
                    case ZIFL:
                        return ZIL;
                    case IF:
                        return INT;
                    case ZIF:
                    case ZI:
                        return ZI;
                    default:
                }
            case ZIFL:
                return b;
            case IF:
                switch (b) {
                    case ZIL:

View on GitHub (pinned to b5bda4fb49)