{"record":{"id":"e5ff2e3606582cd4","repo":"beemdevelopment/Aegis","slug":"not-a-serialized-java-object","errorCode":null,"errorMessage":"Not a serialized Java Object","messagePattern":"Not a serialized Java Object","errorType":"exception","errorClass":"ParseException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/com/beemdevelopment/aegis/importers/FreeOtpImporter.java","lineNumber":378,"sourceCode":"\n        private static final byte TC_NULL = 0x70;\n        private static final byte TC_CLASSDESC = 0x72;\n        private static final byte TC_OBJECT = 0x73;\n        private static final byte TC_STRING = 0x74;\n\n        private SerializedHashMapParser() {\n\n        }\n\n        public static Map<String, String> parse(DataInputStream inStream)\n                throws IOException, ParseException {\n            Map<String, String> map = new HashMap<>();\n\n            // Read/validate the magic number and version\n            int magic = inStream.readUnsignedShort();\n            int version = inStream.readUnsignedShort();\n            if (magic != MAGIC || version != VERSION) {\n                throw new ParseException(\"Not a serialized Java Object\");\n            }\n\n            // Read the class descriptor info for HashMap\n            byte b = inStream.readByte();\n            if (b != TC_OBJECT) {\n                throw new ParseException(\"Expected an object, found: \" + b);\n            }\n            b = inStream.readByte();\n            if (b != TC_CLASSDESC) {\n                throw new ParseException(\"Expected a class desc, found: \" + b);\n            }\n            parseClassDescriptor(inStream);\n\n            // Not interested in the capacity of the map\n            inStream.readInt();\n            // Read the number of elements in the HashMap\n            int size = inStream.readInt();\n","sourceCodeStart":360,"sourceCodeEnd":396,"githubUrl":"https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/app/src/main/java/com/beemdevelopment/aegis/importers/FreeOtpImporter.java#L360-L396","documentation":"FreeOtpImporter.parse manually decodes a Java-serialized stream with a DataInputStream instead of ObjectInputStream. It first reads the stream's magic number (0xACED) and version and throws this ParseException when either does not match, i.e. the data is not a Java serialization stream at all. This is a fast-fail guard against feeding the parser a wrong or corrupt file.","triggerScenarios":"Calling parse() on a file whose first 4 bytes are not the Java serialization magic 0xAC ED followed by the expected version — for example an plain-text/JSON export, a ZIP, or a truncated file.","commonSituations":"User selects the wrong file during FreeOTP import (e.g. the app's preferences XML or a database file instead of the serialized tokens file), or the export was converted/re-saved by another tool that changed the format.","solutions":["Confirm the selected file is the actual FreeOTP serialized token file (starts with bytes AC ED 00 05).","Re-export the tokens from FreeOTP and retry the import.","Do not convert, edit, or re-save the export file before importing.","Update Aegis and FreeOTP to latest versions in case the stream version constant changed."],"exampleFix":"// before: wrong file given to the importer\nbyte[] data = readBytes(\"freeotp-backup.json\"); // not a Java-serialized stream\n// after: verify the magic header before importing\nbyte[] data = readBytes(\"freeotp-backup.bin\");\nif (!(data[0] == (byte) 0xAC && data[1] == (byte) 0xED)) {\n    throw new ParseException(\"File is not a Java-serialized FreeOTP export\");\n}","handlingStrategy":"validation","validationCode":"static void validateJavaSerializationHeader(byte[] data) {\n    if (data == null || data.length < 4) throw new ParseException(\"File too short\");\n    int magic = ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);\n    if (magic != 0xACED) throw new ParseException(\"Not a Java serialization stream\");\n}","typeGuard":"static boolean isJavaSerializedStream(byte[] data) {\n    return data != null && data.length >= 4\n        && data[0] == (byte) 0xAC && data[1] == (byte) 0xED;\n}","tryCatchPattern":"try {\n    importer.parse(stream);\n} catch (ParseException e) {\n    if (e.getMessage().contains(\"Not a serialized Java Object\")) {\n        // file is not a Java-serialized export; prompt user to pick the correct file\n        showWrongFileError();\n    }\n}","preventionTips":["Check the first bytes (AC ED 00 05) of the file before attempting import.","Never convert FreeOTP exports to text/JSON formats before importing.","Keep the original export file; re-export from FreeOTP if in doubt.","Distinguish FreeOTP's token store file from its other serialized files by size/content."],"tags":["java","android","importer","serialization","freeotp"],"backgroundTag":"invalid-argument-format","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"}