{"record":{"id":"1996adad2b6f7925","repo":"MuntashirAkon/AppManager","slug":"couldn-t-fully-read-data","errorCode":null,"errorMessage":"Couldn't fully read data","messagePattern":"Couldn't fully read data","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/github/muntashirakon/AppManager/backup/adb/AndroidBackupHeader.java","lineNumber":340,"sourceCode":"    @NonNull\n    private static String readHeaderLine(@NonNull InputStream in) throws IOException {\n        int c;\n        StringBuilder buffer = new StringBuilder(80);\n        while ((c = in.read()) >= 0) {\n            if (c == '\\n') {\n                break;   // consume and discard the newlines\n            }\n            buffer.append((char) c);\n        }\n        return buffer.toString();\n    }\n\n    private static void readFullyOrThrow(InputStream in, byte[] buffer) throws IOException {\n        int offset = 0;\n        while (offset < buffer.length) {\n            int bytesRead = in.read(buffer, offset, buffer.length - offset);\n            if (bytesRead <= 0) {\n                throw new IOException(\"Couldn't fully read data\");\n            }\n            offset += bytesRead;\n        }\n    }\n\n    /**\n     * Generates {@link SecretKey} instance from given parameters and returns it's checksum.\n     * <p>\n     * Current implementation returns the key in its primary encoding format.\n     *\n     * @param algorithm - key generation algorithm.\n     * @param pwBytes   - password.\n     * @param salt      - salt.\n     * @param rounds    - number of rounds to run in key generation.\n     * @return Hex representation of the generated key, or null if generation failed.\n     */\n    @NonNull\n    public static byte[] makeKeyChecksum(String algorithm, byte[] pwBytes, byte[] salt, int rounds)","sourceCodeStart":322,"sourceCodeEnd":358,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/io/github/muntashirakon/AppManager/backup/adb/AndroidBackupHeader.java#L322-L358","documentation":"readFullyOrThrow is a helper that loops on InputStream.read until the requested buffer is completely filled. If the stream returns <= 0 bytes before the buffer is full (EOF or stream error), it throws IOException(\"Couldn't fully read data\"). This guards fixed-size header reads in the ADB backup protocol from silently proceeding with partial data.","triggerScenarios":"Reading the Android backup header over the ADB local socket when the stream ends prematurely: `adb backup` aborts before sending the full header, the peer closes the socket, or the backup file/socket supplies fewer bytes than the expected header length.","commonSituations":"User confirms backup on device but cancels immediately; encrypted backup password dialog interaction breaks the stream; truncated or corrupted .ab backup file being parsed; device disconnected mid-handshake.","solutions":["Retry the backup operation and ensure the device stays connected until `adb backup` completes","Verify the .ab file is not truncated: compare its size with the expected header + payload, re-create the backup if corrupt","Check that the ADB backup flow (password confirmation dialog on device) was fully completed","If parsing a file, open it via FileInputStream rather than a socket and confirm file length >= header size"],"exampleFix":"// before\nin.read(buffer); // assumes single read fills buffer / no completeness check\n// after\nreadFullyOrThrow(in, buffer); // throws IOException instead of silently using partial header","handlingStrategy":"try-catch","validationCode":"// Ensure the source supplies at least the expected header bytes\nif (available < expectedHeaderLength) throw new IOException(\"Source too short for backup header\");","typeGuard":"static boolean hasEnoughBytes(InputStream in, int needed) throws IOException {\n    return in.available() >= needed; // heuristic pre-check; readFullyOrThrow remains authoritative\n}","tryCatchPattern":"try {\n    AndroidBackupHeader.read(in);\n} catch (IOException e) {\n    if (\"Couldn't fully read data\".equals(e.getMessage())) {\n        // treat as truncated/corrupt backup: abort and re-create the backup\n    }\n}","preventionTips":["Keep the device connected until adb backup fully completes","Do not cancel the on-device backup confirmation dialog","Validate .ab file size before parsing","Retry once on transient stream failures"],"tags":["io","adb","backup","stream"],"backgroundTag":"file-read-failed","analyzedSha":"0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5","analyzedAt":"2026-09-12T14:03:37.243Z","contentChangedAt":"2026-09-12T14:03:37.243Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}