{"record":{"id":"549eedf5ad445f99","repo":"MuntashirAkon/AppManager","slug":"truncated-tar-archive","errorCode":null,"errorMessage":"Truncated TAR archive","messagePattern":"Truncated TAR archive","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java","lineNumber":465,"sourceCode":"\n    /**\n     * For FileInputStream, the skip always return the number you input, so we\n     * need the available bytes to determine how many bytes are actually skipped\n     *\n     * @param available available bytes returned by inputStream.available()\n     * @param skipped   skipped bytes returned by inputStream.skip()\n     * @param expected  bytes expected to skip\n     * @return number of bytes actually skipped\n     * @throws IOException if a truncated tar archive is detected\n     */\n    private long getActuallySkipped(final long available, final long skipped, final long expected) throws IOException {\n        long actuallySkipped = skipped;\n        if (inputStream instanceof FileInputStream) {\n            actuallySkipped = Math.min(skipped, available);\n        }\n\n        if (actuallySkipped != expected) {\n            throw new IOException(\"Truncated TAR archive\");\n        }\n\n        return actuallySkipped;\n    }\n\n    /**\n     * Get the next entry in this tar archive as longname data.\n     *\n     * @return The next entry in the archive as longname data, or null.\n     * @throws IOException on error\n     */\n    protected byte[] getLongNameData() throws IOException {\n        // read in the name\n        final ByteArrayOutputStream longName = new ByteArrayOutputStream();\n        int length = 0;\n        while ((length = read(smallBuf)) >= 0) {\n            longName.write(smallBuf, 0, length);\n        }","sourceCodeStart":447,"sourceCodeEnd":483,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java#L447-L483","documentation":"Thrown by getActuallySkipped when the underlying stream could not skip as many bytes as requested while reading an entry or its padding. Because skipping fewer bytes than expected desynchronizes the parser, the stream reports the archive as truncated.","triggerScenarios":"skip(long) or skipRecordPadding() reaches EOF before the full entry data/padding has been consumed — the archive file is shorter than its headers claim.","commonSituations":"Partially downloaded or interrupted transfers; archives copied with truncation (disk-full during copy); reading a still-being-written tar.","solutions":["Verify the archive's size against the source (re-download; compare byte counts/hashes)","Use streams that report correct available/skip semantics (avoid wrapping in streams that short-circuit skip)","Wait until writing of the tar is complete before reading","Catch IOException, and consider implementing a manual read-loop skip for streams with unreliable skip"],"exampleFix":"// before\nlong n = in.skip(entrySize); // may skip fewer bytes silently elsewhere\n// after\nlong remaining = entrySize;\nbyte[] buf = new byte[8192];\nwhile (remaining > 0) {\n    long r = in.read(buf, 0, (int) Math.min(buf.length, remaining));\n    if (r < 0) throw new IOException(\"Truncated TAR archive\");\n    remaining -= r;\n}","handlingStrategy":"try-catch","validationCode":"if (archiveFile.length() < expectedMinimumSize) {\n    throw new IOException(\"archive incomplete\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    // iterate entries, read data\n} catch (IOException e) {\n    if (e.getMessage().contains(\"Truncated TAR archive\")) {\n        throw new IOException(\"Archive incomplete — re-download required\", e);\n    }\n    throw e;\n}","preventionTips":["Verify file size/hash after download before extraction","Only read completed archives","Prefer explicit read-loops over skip() for untrusted streams"],"tags":["tar","truncation","io"],"backgroundTag":"truncated-archive","analyzedSha":"0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5","analyzedAt":"2026-09-12T14:03:37.243Z","contentChangedAt":"2026-09-12T14:03:37.243Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}