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

  1. Run the latest jadx release.
  2. Log type and type.getPrimitiveType() at the throw site to identify which ArgType is invalid.
  3. Trace upstream: find which instruction/arg supplied the literal and fix type inference there instead of at the throw site.
  4. Submit a minimal reproducer to jadx.
  5. 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

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


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