{"record":{"id":"df27c8fff8e7725f","repo":"MuntashirAkon/AppManager","slug":"this-archive-has-already-been-finished","errorCode":null,"errorMessage":"This archive has already been finished","messagePattern":"This archive has already been finished","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java","lineNumber":272,"sourceCode":"\n    @Override\n    public long getBytesWritten() {\n        return countingOut.getBytesWritten();\n    }\n\n    /**\n     * Ends the TAR archive without closing the underlying OutputStream.\n     *\n     * An archive consists of a series of file entries terminated by an\n     * end-of-archive entry, which consists of two 512 blocks of zero bytes.\n     * POSIX.1 requires two EOF records, like some other implementations.\n     *\n     * @throws IOException on error\n     */\n    @Override\n    public void finish() throws IOException {\n        if (finished) {\n            throw new IOException(\"This archive has already been finished\");\n        }\n\n        if (haveUnclosedEntry) {\n            throw new IOException(\"This archive contains unclosed entries.\");\n        }\n        writeEOFRecord();\n        writeEOFRecord();\n        padAsNeeded();\n        out.flush();\n        finished = true;\n    }\n\n    /**\n     * Closes the underlying OutputStream.\n     *\n     * @throws IOException on error\n     */\n    @Override","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java#L254-L290","documentation":"TarArchiveOutputStream.finish() writes the end-of-archive records; calling it more than once is invalid, so the second call throws IOException because the internal 'finished' flag is already set. close() calls finish(), so manual finish() followed by close() triggers this.","triggerScenarios":"Calling finish() then close(); calling finish() twice; wrapping the stream in code that both finishes and closes (e.g. try-with-resources after an explicit finish()).","commonSituations":"Manual resource management without try-with-resources; helper methods that finish the archive while a caller also closes it; retry logic that re-invokes finish after a partial failure.","solutions":["Call finish() only once, or rely on close() which finishes automatically.","Track whether you already finished and skip the second call.","If using try-with-resources, remove the explicit finish() call."],"exampleFix":"// before\ntar.finish();\ntar.close(); // finish() runs again -> throws\n// after\ntar.close(); // close() finishes the archive exactly once","handlingStrategy":"try-catch","validationCode":"// Track finish state yourself\nboolean archiveFinished = false;\nif (!archiveFinished) { tar.finish(); archiveFinished = true; }","typeGuard":null,"tryCatchPattern":"try {\n    tar.finish();\n} catch (IOException e) {\n    if (!\"This archive has already been finished\".equals(e.getMessage())) throw e;\n    // already finished: safe to ignore\n}","preventionTips":["Prefer close() alone — it finishes exactly once","Use try-with-resources","Do not call finish() and close() both in helper chains"],"tags":["tar","stream-state","double-close","invalid-state"],"backgroundTag":"invalid-state-transition","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"}