skylot/jadx · error · JadxRuntimeException
Unexpected key in switch:
Error message
Unexpected key in switch:
What it means
Thrown by RegionGen.addCaseKey when decompiling a switch statement whose case key is not one of the four supported kinds: a FieldNode (enum constant), a FieldInfo, an Integer, or a String. The switch-codegen path expects every case key object to match one of these instanceof branches; anything else reaches the else and aborts. It is an internal invariant failure during Java-source emission.
Source
Thrown at jadx-core/src/main/java/jadx/core/codegen/RegionGen.java:284
}
makeRegionIndent(code, c);
}
code.decIndent();
code.startLine('}');
}
private void addCaseKey(ICodeWriter code, InsnArg arg, Object k) throws CodegenException {
if (k instanceof FieldNode) {
FieldNode fld = (FieldNode) k;
useField(code, fld.getFieldInfo(), fld);
} else if (k instanceof FieldInfo) {
useField(code, (FieldInfo) k, null);
} else if (k instanceof Integer) {
code.add(TypeGen.literalToString((Integer) k, arg.getType(), mth, fallback));
} else if (k instanceof String) {
code.add('\"').add((String) k).add('\"');
} else {
throw new JadxRuntimeException("Unexpected key in switch: " + (k != null ? k.getClass() : null));
}
}
private void useField(ICodeWriter code, FieldInfo fldInfo, @Nullable FieldNode fld) throws CodegenException {
boolean isEnum;
if (fld != null) {
isEnum = fld.getParentClass().isEnum();
} else {
ClspClass clsDetails = root.getClsp().getClsDetails(fldInfo.getDeclClass().getType());
isEnum = clsDetails != null && clsDetails.hasAccFlag(AccessFlags.ENUM);
}
if (isEnum) {
if (fld != null) {
code.attachAnnotation(fld);
}
code.add(fldInfo.getAlias());
return;
}View on GitHub (pinned to e738a26571)
Solutions
- Reproduce on the latest jadx release / master; switch key handling has been extended across versions.
- Locate the offending class: enable verbose/debug logging, find which class/method triggers decompilation, and isolate that input.
- Inspect the key object: add a temporary log of k.getClass() and k before the else, then decide whether to add a branch (e.g. Long -> literalToString) or fix the upstream pass that produced the wrong key type.
- File a jadx bug with the minimal APK/DEX that reproduces and the full stack trace.
- As a workaround, exclude the problematic class from decompilation (--no-debug / selective class filters) so the rest of the output completes.
Example fix
// before
} else {
throw new JadxRuntimeException("Unexpected key in switch: " + (k != null ? k.getClass() : null));
}
// after (support additional key kinds, e.g. Long)
} else if (k instanceof Long) {
code.add(TypeGen.literalToString(((Long) k).intValue(), arg.getType(), mth, fallback)).add('L');
} else {
throw new JadxRuntimeException("Unexpected key in switch: " + (k != null ? k.getClass() : null));
} Defensive patterns
Strategy: type-guard
Validate before calling
// Before invoking switch codegen on a case, narrow the key type
boolean supported = k instanceof FieldNode || k instanceof FieldInfo
|| k instanceof Integer || k instanceof String;
if (!supported) {
LOG.warn("Skipping unsupported switch key type: {}", k != null ? k.getClass() : null);
} Type guard
static boolean isSupportedSwitchKey(Object k) {
return k instanceof FieldNode || k instanceof FieldInfo
|| k instanceof Integer || k instanceof String;
} Try / catch
// Wrap the per-class decompile boundary; the throw carries the class context upstream
try {
classNode.decompile();
} catch (JadxRuntimeException e) {
LOG.warn("Switch codegen failed for {}, skipping: {}", classNode, e.getMessage());
classNode.add(AFlag.INCONSISTENT_CODE);
} Prevention
- Keep jadx on a current release - switch-key coverage improves over time.
- Isolate failing inputs to a minimal class before reporting.
- Treat decompiler aborts as per-class failures, not whole-batch failures, by decompiling each class in its own try/catch.
When it happens
Trigger: Decompiling a DEX/bytecode input that contains a packed/sparse switch or a string switch whose case key was built by an earlier pass into a type jadx does not recognise (e.g. a Long, a raw ArgType, a method handle, or a custom InsnArg wrapper). Also reachable when switch-type-inference falls back to a non-standard key representation for obfuscated inputs.
Common situations: Heavily obfuscated or packed APKs; inputs produced by unusual compilers/transformers; running with an unstable jadx build where a pass left a half-transformed key; mixing versions of jadx plugins that produce key objects the core does not understand.
Related errors
- Unexpected arg type in catch block:
- Unknown type in literalToString:
- 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/80d264208ebb65a6.
Report an issue: GitHub.