Konloch/bytecode-viewer · error · ClassFileFormatException

Invalid internal class name

Error message

Invalid internal class name

What it means

JDGUIClassFileUtil maps a JVM internal class name (slashes instead of dots) to its .class file path inside an archive. When the computed path suffix (internal name with '/' replaced by the platform separator, plus '.class') cannot be located in the discovered path, it throws ClassFileFormatException('Invalid internal class name'), aborting decompilation of that entry. This protects the decompiler from operating on entries that don't correspond to a real class file layout.

Source

Thrown at src/main/java/the/bytecode/club/bytecodeviewer/decompilers/jdgui/JDGUIClassFileUtil.java:87

            if ((c == null) || (c.getTag() != Constant.CONSTANT_Class))
            {
                throw new ClassFileFormatException("Invalid constant pool");
            }

            c = constants[((ConstantClass) c).getNameIndex()];
            if ((c == null) || (c.getTag() != Constant.CONSTANT_Utf8))
            {
                throw new ClassFileFormatException("Invalid constant pool");
            }

            String internalClassName = ((ConstantUtf8) c).getValue();
            String pathSuffix = internalClassName.replace(INTERNAL_PACKAGE_SEPARATOR, File.separatorChar) + CLASS_FILE_SUFFIX;

            int index = pathToClass.indexOf(pathSuffix);

            if (index < 0)
            {
                throw new ClassFileFormatException("Invalid internal class name");
            }

            directoryPath = pathToClass.substring(0, index);
        }
        catch (IOException e)
        {
            directoryPath = null;
            e.printStackTrace();
        }

        return directoryPath;
    }

    public static String ExtractInternalPath(String directoryPath, String pathToClass)
    {
        if ((directoryPath == null) || (pathToClass == null) || !pathToClass.startsWith(directoryPath))
            return null;

View on GitHub (pinned to 31430e0033)

Solutions

  1. Verify the jar's directory layout matches each class's package (com/foo/Bar.class for com.foo.Bar)
  2. Re-decompile from the original, un-obfuscated jar or disable obfuscation in the build
  3. If it's an inner class, ensure Outer$Inner.class entries are present in the archive
  4. Catch ClassFileFormatException and fall back to another decompiler (e.g. CFR, FernFlower) for that entry
  5. If the jar was built on another OS, normalize paths instead of relying on File.separatorChar

Example fix

// before
String pathSuffix = internalClassName.replace('.', '/') + ".class";
int index = pathToClass.indexOf(pathSuffix);
if (index < 0) throw new ClassFileFormatException("Invalid internal class name");
// after
String normalized = internalClassName.replace('.', '/').replace('$', '/');
String pathSuffix = normalized + ".class";
int index = pathToClass.indexOf(pathSuffix);
if (index < 0) {
    index = pathToClass.indexOf(internalClassName.replace('.', '/') + ".class"); // retry with $ kept
}
if (index < 0) throw new ClassFileFormatException("Invalid internal class name: " + internalClassName);
Defensive patterns

Strategy: try-catch

Validate before calling

String expected = internalClassName.replace('.', '/') + ".class";
boolean exists = classLoader.getResource(expected) != null || jarEntries.contains(expected);
if (!exists) throw new IllegalArgumentException("No class file for " + internalClassName);

Type guard

boolean isValidInternalName(String name) {
    return name != null && name.matches("[\\w/$]+");
}

Try / catch

try {
    decompileWithJdGui(internalClassName, bytes);
} catch (ClassFileFormatException e) {
    LOGGER.warn("Skipping " + internalClassName + ": " + e.getMessage());
    fallbackDecompiler.decompile(internalClassName, bytes);
}

Prevention

When it happens

Trigger: Calling the JD-GUI decompiler on a class whose internal name does not match the archive's directory structure: e.g. obfuscated/renamed class names, class names containing dots or special characters that were replaced by INTERNAL_PACKAGE_SEPARATOR, anonymous/inner classes whose binary name (Outer$Inner) doesn't map to a file the util can find, or decompiling a non-class resource mistakenly routed to this util.

Common situations: Decompiling obfuscated jars (ProGuard/Rename targets) where names no longer match paths; jars built on different OSes with mismatched path separators; jars repackaged so class files move relative to their package path; inner/anonymous classes in frameworks like Mockito or GUI builders; feeding a .class resource that lives outside the expected package directory.

Related errors


AI-assisted analysis of Konloch/bytecode-viewer@31430e0033 (2026-09-05). Data as JSON: /api/errors/3d76cde4b01b52f3. Report an issue: GitHub.