{"record":{"id":"8956752099322243","repo":"beemdevelopment/Aegis","slug":"expected-a-string-object-found-d","errorCode":null,"errorMessage":"Expected a string object, found: %d","messagePattern":"Expected a string object, found: (.+?)","errorType":"exception","errorClass":"ParseException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/com/beemdevelopment/aegis/importers/FreeOtpImporter.java","lineNumber":448,"sourceCode":"                    case 'F': // float (4 bytes)\n                    case 'I': // int (4 bytes)\n                        totalFieldSkip += 4;\n                        break;\n                    default:\n                        throw new ParseException(String.format(\"Unexpected field type: %s\", fieldType));\n                }\n            }\n            inputStream.skipBytes(totalFieldSkip);\n\n            // Not sure what these bytes are, just skip them\n            inputStream.skipBytes(4);\n        }\n\n        private static String parseStringObject(DataInputStream inputStream)\n                throws IOException, ParseException {\n            byte objectType = inputStream.readByte();\n            if (objectType != TC_STRING) {\n                throw new ParseException(String.format(\"Expected a string object, found: %d\", objectType));\n            }\n\n            int length = inputStream.readUnsignedShort();\n            byte[] strBytes = new byte[length];\n            inputStream.readFully(strBytes);\n\n            return new String(strBytes, StandardCharsets.UTF_8);\n        }\n\n        private static String parseUTF(DataInputStream inputStream) throws IOException {\n            int length = inputStream.readUnsignedShort();\n            byte[] strBytes = new byte[length];\n            inputStream.readFully(strBytes);\n            return new String(strBytes, StandardCharsets.UTF_8);\n        }\n\n        private static class ParseException extends Exception {\n            public ParseException(String message) {","sourceCodeStart":430,"sourceCodeEnd":466,"githubUrl":"https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/app/src/main/java/com/beemdevelopment/aegis/importers/FreeOtpImporter.java#L430-L466","documentation":"SerializedHashMapParser.parseStringObject reads the next byte of the serialized FreeOTP stream expecting a TC_STRING marker (a Java serialized string object). Any other object type code means the parser's expectations about the HashMap's contents no longer line up with the actual stream, so it throws this ParseException.","triggerScenarios":"During parse(), when consuming keys/values of the serialized HashMap, a byte that is not TC_STRING appears where a string object is expected — e.g. the map holds non-String values, the offset is misaligned due to earlier skipped bytes, or the file isn't a FreeOTP backup.","commonSituations":"Backups from modified FreeOTP versions storing extra object types; importing a different app's Java-serialized HashMap; a parsing offset bug after the class-descriptor skip produced desynchronized reads.","solutions":["Re-export tokens from the stock FreeOTP app and retry the import.","Verify the file is a FreeOTP backup (serialized HashMap of String->String) rather than another serialized object.","Check whether earlier skip logic (field descriptors, trailing 4 bytes) misaligned the stream for this producer version and adjust skipBytes accordingly.","Dump the serialized stream to inspect object graph and confirm where the non-string object appears."],"exampleFix":"// before\nbyte objectType = inputStream.readByte();\nif (objectType != TC_STRING) {\n    throw new ParseException(String.format(\"Expected a string object, found: %d\", objectType));\n}\n// after: tolerate known non-string markers where appropriate\nbyte objectType = inputStream.readByte();\nif (objectType == TC_NULL) { return null; }\nif (objectType != TC_STRING) {\n    throw new ParseException(String.format(\"Expected a string object, found: %d\", objectType));\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    importer.importFromUri(uri);\n} catch (DatabaseImporterException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"Expected a string object\")) {\n        showError(\"The backup layout differs from what the importer expects; re-export from stock FreeOTP.\");\n    }\n}","preventionTips":["Use backups produced only by the stock FreeOTP app.","Ensure the whole file is transferred intact (partial files desynchronize parsing).","Test imports on a small export first.","Keep Aegis updated so skip-logic matches current FreeOTP output."],"tags":["java-serialization","importer","format-mismatch"],"backgroundTag":"unexpected-api-response-shape","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"}