{"record":{"id":"756d8c33abdcfec4","repo":"Tencent/tinker","slug":"unknown-output-extension-file","errorCode":null,"errorMessage":"unknown output extension: ${file}","messagePattern":"unknown output extension: (.+?)","errorType":"exception","errorClass":"DexException","httpStatus":null,"severity":"error","filePath":"third-party/aosp-dexutils/src/main/java/com/tencent/tinker/android/dex/Dex.java","lineNumber":176,"sourceCode":"            }\n        } else if (file.getName().endsWith(\".dex\")) {\n            InputStream in = null;\n            try {\n                in = new BufferedInputStream(new FileInputStream(file));\n                loadFrom(in, (int) file.length());\n            } catch (Exception e) {\n                throw new DexException(e);\n            } finally {\n                if (in != null) {\n                    try {\n                        in.close();\n                    } catch (Exception e) {\n                        // ignored.\n                    }\n                }\n            }\n        } else {\n            throw new DexException(\"unknown output extension: \" + file);\n        }\n    }\n\n    private static void checkBounds(int index, int length) {\n        if (index < 0 || index >= length) {\n            throw new IndexOutOfBoundsException(\"index:\" + index + \", length=\" + length);\n        }\n    }\n\n    private void loadFrom(InputStream in) throws IOException {\n        loadFrom(in, 0);\n    }\n\n    private void loadFrom(InputStream in, int initSize) throws IOException {\n        byte[] rawData = FileUtils.readStream(in, initSize);\n        this.data = ByteBuffer.wrap(rawData);\n        this.data.order(ByteOrder.LITTLE_ENDIAN);\n        this.tableOfContents.readFrom(this);","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/Tencent/tinker/blob/1b7ea02c239840f563ea64fb5bd286eb98d4011e/third-party/aosp-dexutils/src/main/java/com/tencent/tinker/android/dex/Dex.java#L158-L194","documentation":"Thrown by Dex(File) when the file name does not end with a recognized archive suffix (.zip/.jar/.apk via FileUtils.hasArchiveSuffix) nor with .dex. The constructor dispatches purely on the file-name extension, so any other spelling is rejected without reading the file.","triggerScenarios":"new Dex(new File(\"classes_dex.bak\")), renamed artifacts, uppercase extensions (.DEX — hasArchiveSuffix/.endsWith are case-sensitive), or temp files whose suffix was changed mid-pipeline.","commonSituations":"Build pipelines that stage files under temporary names (foo.dex.tmp) and pass them before renaming; case-mismatched extensions on case-insensitive filesystems; files downloaded with the wrong suffix.","solutions":["Rename/copy the file to a literal .dex extension (or a proper archive suffix) before constructing Dex.","Feed the bytes in via new Dex(InputStream/byte[]) to bypass name-based dispatch entirely.","Check the exact filename string at runtime (case-sensitive) if the path is composed dynamically."],"exampleFix":"// before\nDex dex = new Dex(stagedFile); // stagedFile = \"patch.0352.tmp\"\n\n// after\nFile renamed = new File(stagedFile.getParentFile(), stagedFile.getName() + \".dex\");\nFiles.copy(stagedFile.toPath(), renamed.toPath(), StandardCopyOption.REPLACE_EXISTING);\nDex dex = new Dex(renamed);","handlingStrategy":"validation","validationCode":"String n = file.getName().toLowerCase(Locale.ROOT);\nif (!(n.endsWith(\".dex\") || n.endsWith(\".zip\") || n.endsWith(\".jar\") || n.endsWith(\".apk\"))) {\n    throw new IllegalArgumentException(\"unsupported dex input name: \" + n);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Normalize temp artifacts to their final .dex/.apk name before parsing.","Remember extension checks here are case-sensitive; lowercase the name when composing paths dynamically."],"tags":["dex","file-extension","tinker"],"backgroundTag":null,"analyzedSha":"1b7ea02c239840f563ea64fb5bd286eb98d4011e","analyzedAt":"2026-08-14T15:16:52.110Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}