{"record":{"id":"e94b9beab12e3a48","repo":"beemdevelopment/Aegis","slug":"unexpected-serial-version-uid-d","errorCode":null,"errorMessage":"Unexpected serial version UID: %d","messagePattern":"Unexpected serial version UID: (.+?)","errorType":"exception","errorClass":"ParseException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/com/beemdevelopment/aegis/importers/FreeOtpImporter.java","lineNumber":416,"sourceCode":"            for (int i = 0; i < size; i++) {\n                String key = parseStringObject(inStream);\n                String value = parseStringObject(inStream);\n                map.put(key, value);\n            }\n\n            return map;\n        }\n\n        private static void parseClassDescriptor(DataInputStream inputStream)\n                throws IOException, ParseException {\n            // Check whether we're dealing with a HashMap and a version we support\n            String className = parseUTF(inputStream);\n            if (!className.equals(HashMap.class.getName())) {\n                throw new ParseException(String.format(\"Unexpected class name: %s\", className));\n            }\n            long serialVersionUID = inputStream.readLong();\n            if (serialVersionUID != SERIAL_VERSION_UID) {\n                throw new ParseException(String.format(\"Unexpected serial version UID: %d\", serialVersionUID));\n            }\n\n            // Read past all of the fields in the class\n            byte fieldDescriptor = inputStream.readByte();\n            if (fieldDescriptor == TC_NULL) {\n                return;\n            }\n            int totalFieldSkip = 0;\n            int fieldCount = inputStream.readUnsignedShort();\n            for (int i = 0; i < fieldCount; i++) {\n                char fieldType = (char) inputStream.readByte();\n                parseUTF(inputStream);\n                switch (fieldType) {\n                    case 'F': // float (4 bytes)\n                    case 'I': // int (4 bytes)\n                        totalFieldSkip += 4;\n                        break;\n                    default:","sourceCodeStart":398,"sourceCodeEnd":434,"githubUrl":"https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/app/src/main/java/com/beemdevelopment/aegis/importers/FreeOtpImporter.java#L398-L434","documentation":"FreeOtpImporter.parseClassDescriptor manually parses a Java serialized stream of a FreeOTP backup. It expects the stream's class descriptor to declare java.util.HashMap with the exact expected serialVersionUID (SERIAL_VERSION_UID). If the embedded long differs, it throws this ParseException, meaning the file is not the Java-serialized HashMap format this importer knows how to read.","triggerScenarios":"Importing a FreeOTP backup whose serialized HashMap has a serialVersionUID other than the hardcoded SERIAL_VERSION_UID — e.g. the file was produced by a different app version, a different serialization library, or is a truncated/re-exported file.","commonSituations":"Users export tokens from an updated or forked FreeOTP build with a changed serialVersionUID; the selected file is actually not a FreeOTP backup (wrong file chosen); the file was corrupted during transfer or partially rewritten by another tool.","solutions":["Re-export the FreeOTP tokens from the original FreeOTP app version and import that file.","Verify the selected file is the actual FreeOTP backup (a Java-serialized HashMap), not a JSON/other export.","Check that the file is not corrupted — compare size/hash against the export source.","If a legitimate new serialVersionUID must be supported, update SERIAL_VERSION_UID in FreeOtpImporter to match the producing version."],"exampleFix":"// before: importing a mis-exported/wrong file\nimporter.importFromUri(wrongBackupUri);\n// after: validate format upstream or re-export from stock FreeOTP\nif (!isFreeOtpBackup(file)) { showUserError(\"Select a FreeOTP backup\"); return; }\nimporter.importFromUri(freeOtpBackupUri);","handlingStrategy":"try-catch","validationCode":"// Peek at the file header; Java-serialized streams start with 0xAC 0xED\nbyte[] head = new byte[2];\ntry (InputStream is = contentResolver.openInputStream(uri)) {\n    if (is == null || is.read(head) != 2 || head[0] != (byte)0xAC || head[1] != (byte)0xED) {\n        throw new IllegalArgumentException(\"Not a FreeOTP (Java serialized) backup\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    DatabaseImporter.EntryResult res = importer.importFromUri(uri);\n} catch (DatabaseImporterException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"serial version UID\")) {\n        showError(\"This backup is not compatible with this importer; re-export from stock FreeOTP.\");\n    }\n}","preventionTips":["Only export FreeOTP tokens using the stock FreeOTP app version.","Validate the file's Java-serialization magic bytes before importing.","Keep a hash of the original export to detect corruption.","Never round-trip the backup through other tools that re-serialize it."],"tags":["java-serialization","importer","format-mismatch"],"backgroundTag":"incompatible-source-type","analyzedSha":"d6f4e5925a97e4e91593f1542085eae03432a759","analyzedAt":"2026-09-08T00:46:31.111Z","contentChangedAt":"2026-09-08T00:46:31.111Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}