skylot/jadx · error · JadxRuntimeException
Unknown type in literalToString:
Error message
Unknown type in literalToString:
What it means
Thrown by TypeGen.literalToString when converting a numeric literal to source text. The switch covers all ArgType primitive kinds (BOOLEAN, CHAR, BYTE, SHORT, INT, LONG, FLOAT, DOUBLE, OBJECT, ARRAY); the default branch fires only when the ArgType's primitive kind is null or an unrecognised value. Effectively an internal type-system invariant failure.
Source
Thrown at jadx-core/src/main/java/jadx/core/codegen/TypeGen.java:103
case INT:
return stringUtils.formatInteger(lit, cast);
case LONG:
return stringUtils.formatLong(lit, cast);
case FLOAT:
return StringUtils.formatFloat(Float.intBitsToFloat((int) lit));
case DOUBLE:
return StringUtils.formatDouble(Double.longBitsToDouble(lit));
case OBJECT:
case ARRAY:
if (lit != 0) {
LOG.warn("Wrong object literal: {} for type: {}", lit, type);
return Long.toString(lit);
}
return "null";
default:
throw new JadxRuntimeException("Unknown type in literalToString: " + type);
}
}
@Nullable
public static String literalToRawString(LiteralArg arg) {
ArgType type = arg.getType();
if (type == null) {
return null;
}
long lit = arg.getLiteral();
switch (type.getPrimitiveType()) {
case BOOLEAN:
return lit == 0 ? "false" : "true";
case CHAR:
return String.valueOf((char) lit);
case BYTE:
case SHORT:View on GitHub (pinned to e738a26571)
Solutions
- Run the latest jadx release.
- Log type and type.getPrimitiveType() at the throw site to identify which ArgType is invalid.
- Trace upstream: find which instruction/arg supplied the literal and fix type inference there instead of at the throw site.
- Submit a minimal reproducer to jadx.
- Workaround: decompile the offending class in fallback/no-debug mode or exclude it.
Example fix
// before
default:
throw new JadxRuntimeException("Unknown type in literalToString: " + type);
// after (graceful fallback for null/unknown primitive)
default:
LOG.warn("Unknown type in literalToString: {}", type);
return Long.toString(lit); Defensive patterns
Strategy: validation
Validate before calling
ArgType type = arg.getType();
if (type == null || type.getPrimitiveType() == null) {
LOG.warn("Refusing literalToString on null/unknown type: {}", type);
return Long.toString(arg.getLiteral());
} Type guard
static boolean hasKnownPrimitive(ArgType t) {
return t != null && t.getPrimitiveType() != null;
} Try / catch
try {
return TypeGen.literalToString(lit, type, mth, fallback);
} catch (JadxRuntimeException e) {
LOG.warn("literalToString failed for type {}: {}", type, e.getMessage());
return Long.toString(lit);
} Prevention
- Never pass ArgType.UNKNOWN or VOID to literalToString; resolve the type first.
- Validate type.getPrimitiveType() is non-null at the call site.
- Investigate type-inference passes that leave types unresolved.
When it happens
Trigger: An ArgType with a null or unknown PrimitiveType is passed to literalToString, e.g. a VOID literal, an ArgType.UNKNOWN, or a type whose getPrimitiveType() returns null (some non-primitive, non-object constructs). Reachable during codegen for any constant/emitted literal.
Common situations: Malformed bytecode where a constant instruction has a missing/unknown type; intermediate type-inference producing ArgType.UNKNOWN; version skew between jadx passes; very obfuscated inputs.
Related errors
- Unexpected key in switch:
- Unexpected arg type in catch block:
- Failed to generate code for class: ${cls.getFullName()}
- Unexpected field type class:
- Can't decode value:
AI-assisted analysis of skylot/jadx@e738a26571 (2026-08-14).
Data as JSON: /api/errors/3368f85c1a16073e.
Report an issue: GitHub.