MuntashirAkon/AppManager · error · IOException

This archive contains unclosed entries.

Error message

This archive contains unclosed entries.

What it means

finish() refuses to finalize the archive while an entry is still open (putArchiveEntry was called without a matching closeArchiveEntry), because writing the end-of-archive records would produce a truncated, invalid tar. The caller must close the current entry first.

Solutions

  1. Call closeArchiveEntry() for every putArchiveEntry() before finishing.
  2. Use try/finally (or try-with-resources on the entry-writing logic) to guarantee closeArchiveEntry runs.
  3. Write exactly currSize bytes so closeArchiveEntry itself succeeds before finish.

Example fix

// before
tar.putArchiveEntry(entry);
tar.write(data);
tar.finish(); // throws: unclosed entry
// after
tar.putArchiveEntry(entry);
try { tar.write(data); } finally { tar.closeArchiveEntry(); }
tar.finish();
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure all entries are closed before finishing
if (openEntryCount > 0) { throw new IllegalStateException("close all entries before finish()"); }

Try / catch

try {
    tar.finish();
} catch (IOException e) {
    if (e.getMessage().contains("unclosed entries")) {
        tar.closeArchiveEntry(); tar.finish();
    } else throw e;
}

Prevention

When it happens

Trigger: Calling finish() or close() after putArchiveEntry(entry) without calling closeArchiveEntry(); an exception in entry-writing code skipping closeArchiveEntry().

Common situations: Early returns/exceptions in the middle of writing an entry; forgetting closeArchiveEntry after copying entry data; conditional code paths that skip entry close.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12). Data as JSON: /api/errors/b0876ddb152e796a. Report an issue: GitHub.

Appendix: source

Thrown at app/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java:276

    }

    /**
     * Ends the TAR archive without closing the underlying OutputStream.
     *
     * An archive consists of a series of file entries terminated by an
     * end-of-archive entry, which consists of two 512 blocks of zero bytes.
     * POSIX.1 requires two EOF records, like some other implementations.
     *
     * @throws IOException on error
     */
    @Override
    public void finish() throws IOException {
        if (finished) {
            throw new IOException("This archive has already been finished");
        }

        if (haveUnclosedEntry) {
            throw new IOException("This archive contains unclosed entries.");
        }
        writeEOFRecord();
        writeEOFRecord();
        padAsNeeded();
        out.flush();
        finished = true;
    }

    /**
     * Closes the underlying OutputStream.
     *
     * @throws IOException on error
     */
    @Override
    public void close() throws IOException {
        try {
            if (!finished) {
                finish();

View on GitHub (pinned to 0152f468fc)