skylot/jadx · error · JadxRuntimeException

Bad name for type variable: {}

Error message

Bad name for type variable: {}

What it means

Thrown by SignatureParser when parsing a JVM generics type-variable reference (the 'T...;' form in a signature string) and the extracted variable name contains a ')' character. A well-formed type variable name is an identifier like 'T' or 'K'; a closing parenthesis indicates the parser has run past the end of the type-variable token into an enclosing method signature, i.e. the signature is malformed or was produced by an aggressive obfuscator. This is a defensive integrity check — jadx refuses to build a generic type from a name that is syntactically impossible in valid bytecode.

Source

Thrown at jadx-core/src/main/java/jadx/core/dex/nodes/parser/SignatureParser.java:149

	}

	public ArgType consumeType() {
		char ch = next();
		switch (ch) {
			case 'L':
				ArgType obj = consumeObjectType(false);
				if (obj != null) {
					return obj;
				}
				break;
			case 'T':
				next();
				mark();
				String typeVarName = consumeUntil(';');
				if (typeVarName != null) {
					consume(';');
					if (typeVarName.contains(")")) {
						throw new JadxRuntimeException("Bad name for type variable: " + typeVarName);
					}
					return ArgType.genericType(typeVarName);
				}
				break;

			case '[':
				return ArgType.array(consumeType());

			case STOP_CHAR:
				return null;

			default:
				// primitive type (one char)
				ArgType type = ArgType.parse(ch);
				if (type != null) {
					return type;
				}
				break;

View on GitHub (pinned to e738a26571)

Solutions

  1. Upgrade to the latest jadx release — signature-parser robustness improvements land frequently and may make this a recoverable warning instead of a crash.
  2. If using jadx as a library, catch JadxRuntimeException around the per-class decompilation call and skip the offending class so the batch continues.
  3. Reproduce with the minimal APK/DEX and file a jadx issue including the full signature string from the error message so the parser can be hardened.
  4. As a stopgap, strip the Signature attribute from the offending class with a bytecode editor (e.g. ASM) before decompiling, trading generics info for a successful decompile.

Example fix

// before — unguarded decompile call
for (JavaClass cls : jadx.getClasses()) {
    String code = cls.getCode();
}

// after — skip class on parser failure
for (JavaClass cls : jadx.getClasses()) {
    try {
        String code = cls.getCode();
    } catch (JadxRuntimeException e) {
        LOG.warn("Skipping {}: {}", cls.getName(), e.getMessage());
    }
}
Defensive patterns

Strategy: try-catch

Try / catch

// Wrap per-class decompilation; malformed signatures are not preventable
for (JavaClass cls : jadx.getClasses()) {
    try {
        String code = cls.getCode();
        results.put(cls.getName(), code);
    } catch (JadxRuntimeException e) {
        LOG.warn("Signature parse error in {}: {}", cls.getName(), e.getMessage());
    }
}

Prevention

When it happens

Trigger: consumeType() hits case 'T', calls consumeUntil(';'), gets a non-null string, then typeVarName.contains(")") is true. This happens when a class or method Signature attribute contains something like 'TT);' — a type variable token that leaks a paren, which violates the JVMS signature grammar.

Common situations: Decompiling APKs obfuscated by tools that corrupt or hand-craft Signature attributes (e.g. some variants of Allatori, custom obfuscators). Also seen with DEX files produced by non-standard compilers or bytecode rewriters that emit invalid generic signatures. Rare with stock javac/d8/r8 output.

Related errors


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