{"record":{"id":"3d76cde4b01b52f3","repo":"Konloch/bytecode-viewer","slug":"invalid-internal-class-name","errorCode":null,"errorMessage":"Invalid internal class name","messagePattern":"Invalid internal class name","errorType":"exception","errorClass":"ClassFileFormatException","httpStatus":null,"severity":"error","filePath":"src/main/java/the/bytecode/club/bytecodeviewer/decompilers/jdgui/JDGUIClassFileUtil.java","lineNumber":87,"sourceCode":"            if ((c == null) || (c.getTag() != Constant.CONSTANT_Class))\n            {\n                throw new ClassFileFormatException(\"Invalid constant pool\");\n            }\n\n            c = constants[((ConstantClass) c).getNameIndex()];\n            if ((c == null) || (c.getTag() != Constant.CONSTANT_Utf8))\n            {\n                throw new ClassFileFormatException(\"Invalid constant pool\");\n            }\n\n            String internalClassName = ((ConstantUtf8) c).getValue();\n            String pathSuffix = internalClassName.replace(INTERNAL_PACKAGE_SEPARATOR, File.separatorChar) + CLASS_FILE_SUFFIX;\n\n            int index = pathToClass.indexOf(pathSuffix);\n\n            if (index < 0)\n            {\n                throw new ClassFileFormatException(\"Invalid internal class name\");\n            }\n\n            directoryPath = pathToClass.substring(0, index);\n        }\n        catch (IOException e)\n        {\n            directoryPath = null;\n            e.printStackTrace();\n        }\n\n        return directoryPath;\n    }\n\n    public static String ExtractInternalPath(String directoryPath, String pathToClass)\n    {\n        if ((directoryPath == null) || (pathToClass == null) || !pathToClass.startsWith(directoryPath))\n            return null;\n","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/Konloch/bytecode-viewer/blob/31430e0033fa220db566b5ef461256727ff6793b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/jdgui/JDGUIClassFileUtil.java#L69-L105","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the jar's directory layout matches each class's package (com/foo/Bar.class for com.foo.Bar)","Re-decompile from the original, un-obfuscated jar or disable obfuscation in the build","If it's an inner class, ensure Outer$Inner.class entries are present in the archive","Catch ClassFileFormatException and fall back to another decompiler (e.g. CFR, FernFlower) for that entry","If the jar was built on another OS, normalize paths instead of relying on File.separatorChar"],"exampleFix":"// before\nString pathSuffix = internalClassName.replace('.', '/') + \".class\";\nint index = pathToClass.indexOf(pathSuffix);\nif (index < 0) throw new ClassFileFormatException(\"Invalid internal class name\");\n// after\nString normalized = internalClassName.replace('.', '/').replace('$', '/');\nString pathSuffix = normalized + \".class\";\nint index = pathToClass.indexOf(pathSuffix);\nif (index < 0) {\n    index = pathToClass.indexOf(internalClassName.replace('.', '/') + \".class\"); // retry with $ kept\n}\nif (index < 0) throw new ClassFileFormatException(\"Invalid internal class name: \" + internalClassName);","handlingStrategy":"try-catch","validationCode":"String expected = internalClassName.replace('.', '/') + \".class\";\nboolean exists = classLoader.getResource(expected) != null || jarEntries.contains(expected);\nif (!exists) throw new IllegalArgumentException(\"No class file for \" + internalClassName);","typeGuard":"boolean isValidInternalName(String name) {\n    return name != null && name.matches(\"[\\\\w/$]+\");\n}","tryCatchPattern":"try {\n    decompileWithJdGui(internalClassName, bytes);\n} catch (ClassFileFormatException e) {\n    LOGGER.warn(\"Skipping \" + internalClassName + \": \" + e.getMessage());\n    fallbackDecompiler.decompile(internalClassName, bytes);\n}","preventionTips":["Check the jar entry exists for the class's binary name before decompiling","Keep class file paths aligned with package declarations; avoid manual repackaging","Obtain internal names from the bytecode (e.g. ASM Type.getInternalName) rather than file paths","Fall back to a second decompiler when one fails","Handle inner-class binary names (Outer$Inner) explicitly"],"tags":["decompiler","classpath","jar","java","format"],"backgroundTag":"class-file-not-found","analyzedSha":"31430e0033fa220db566b5ef461256727ff6793b","analyzedAt":"2026-09-05T18:22:22.725Z","contentChangedAt":"2026-09-05T18:22:22.725Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}