NullPointerException when reading ZIP Archive containing only an empty directory with Java ZipInputStream

Hello Aspose Support Team,

I’ve encountered an issue while using the Aspose.Zip library in my Java project.
Specifically, after creating a ZIP archive that contains only an empty directory, I’m unable to read the archive using Java’s ZipInputStream without getting a NullPointerException.

Here’s a simplified version of the code that demonstrates the issue:

@Test
public void testEmptyDir() throws Exception {
Path testDir = Paths.get(“path/to/temp/folder”).resolve(“zipunzip”);
String zipFileName = “archive.zip”;

Path archivePath = testDir.resolve(zipFileName);
Path sourcePath2 = testDir.resolve("zip2").resolve("sub");

if (!sourcePath2.toFile().mkdirs()) {
    fail("Could not create folder " + sourcePath2);
}

zip(sourcePath2.getParent().toString(), archivePath.toString());

try (ZipInputStream zin = new ZipInputStream(new FileInputStream(archivePath.toFile()))) {
    ZipEntry entry = zin.getNextEntry(); // -> NPE happens here
    String name = entry.getName();
}

}

private void zip(String sourceDir, String zipFileName) {
try (Archive archive = new Archive(new ArchiveEntrySettings())) {
archive.createEntries(sourceDir, false);
archive.save(zipFileName);
}
}

I’m using Aspose.Zip version 24.6 on Java Zulu21.44+17-CA (build 21.0.8+9-LTS) and Windows 11.
Is there a known limitation or specific configuration I should use to avoid this problem? Any help or insight into this issue would be greatly appreciated.

Thank you in advance
Best regards
Matthias

@curmas

It looks like you’re encountering a NullPointerException when trying to read a ZIP archive that contains only an empty directory. This issue can occur because the ZipInputStream may not handle empty entries properly, leading to a null ZipEntry.

Cause: The NullPointerException arises when the ZipInputStream encounters an empty entry, resulting in a null ZipEntry.

Solution: To resolve this, you can add a check to ensure that the ZipEntry is not null before attempting to access its properties. Here’s a modified version of your code that includes this check:

try (ZipInputStream zin = new ZipInputStream(new FileInputStream(archivePath.toFile()))) {
    ZipEntry entry = zin.getNextEntry();
    if (entry != null) {
        String name = entry.getName();
        // Process the entry as needed
    } else {
        System.out.println("No entries found in the ZIP archive.");
    }
}

Additionally, ensure that your ZIP creation logic is correctly adding entries, even if they are empty directories.

Next Steps: If the issue persists after implementing this check, consider updating to the latest version of the Aspose.Zip library, as there may have been fixes or improvements related to handling such cases.

Please implement these changes and let me know if this resolves your issue or if you have any further questions!

Hello support,

thanks for your answer. The NullPointerException is thwown inside call of getNextEntry() as you can see in the following stacktrace

java.util.zip.ZipException: only DEFLATED entries can have EXT descriptor
at java.base/java.util.zip.ZipInputStream.readLOC(ZipInputStream.java:529)
at java.base/java.util.zip.ZipInputStream.getNextEntry(ZipInputStream.java:153)

Any other ideas?

Best regards
Matthias

Hello @curmas
You’ve passed false as the second parameter here: archive.createEntries(sourceDir, false);
If source dir is empty, then the result is the minimal ZIP file that contains only the End of Central Directory record. The whole file is 22 bytes only: 504B0506 00000000 00000000 00000000 00000000 0000.
Does it happen on your side?

Hello @curmas
This is a known limitation of ZipInputStream.
See stackoverflow.com.

Hi Eugene, hi vadimyurko,

thank you for your response. However, I fear there might have been a misunderstanding regarding my initial query and the test code I provided. My goal is to create a ZIP archive that contains solely an empty directory using Aspose.Zip, an operation that unfortunately resulted in an error when trying to unzip the archive with Java’s ZipInputStream.

To elucidate the issue more clearly, I have conducted two separate tests:

  1. Using Aspose.Zip:
    I created a ZIP archive with an exclusively empty directory. Attempting to unzip this archive results in an error.
  2. Using Java’s ZipOutputStream :
    I replicated the process, creating a similar ZIP archive containing only an empty directory. This archive could be unzipped without any issues, indicating the operation is feasible and not a limitation of Java’s ZIP handling.

I believe this strongly suggests the problem lies not with the Java ZIP functionality but possibly with the Aspose.Zip implementation or its handling of empty directories.

For your convenience and a better understanding of the situation, I am attaching both ZIP files created using the respective methods mentioned above. Furthermore, I provide the Java code used for the second test if it helps to clarify the intended operation and facilitate a resolution to this issue (see “ZipCode Example.zip”).

archive_generated_with_java.zip (220 Bytes)
archive_generated_with_aspose.zip (194 Bytes)
ZipCode Example.zip (625 Bytes)

Thank you once again for your support and understanding. Looking forward to your guidance.

Best regards
Matthias

Hi Matthias,
Thank you for the clarification. We will examine the files and return with an answer.

@curmas
We have opened the following new ticket(s) in our internal issue tracking system and will deliver their fixes according to the terms mentioned in Free Support Policies.

Issue ID(s): ZIPNET-1354

You can obtain Paid Support Services if you need support on a priority basis, along with the direct access to our Paid Support management team.

Hello @curmas,

Your files illustrate the ZipInputStream issue mentioned above on StackOverflow.
Both archives are valid (comply with the standard), 7z reports on them are listed below. However, Method: Store + Characteristics: Descriptor combination is a trouble for ZipInputStream to digest.

Perhaps we will change it getting rid of Descriptor header for directory records, probably customizable via settings. This would only work for seekable output stream. Alternative option - set method to deflate - seems an inaccuracy to me. Instead, I am sure it is ZipOutputStream that should apply the Store method to the directory records, as InfoZIP does.

Anyway, we’ll keep you posted.

Listing archive: archive_generated_with_aspose.zip

--
Path = archive_generated_with_aspose.zip
Type = zip
Physical Size = 194

----------
Path = sub\
Folder = +
Size = 0
Packed Size = 0
Modified = 2025-08-07 19:20:51.3789952
Created = 2025-08-07 19:20:51.3789952
Accessed = 2025-08-07 19:20:51.9609984
Attributes = DA
Encrypted = -
Comment = 
CRC = 
Method = Store
Characteristics = NTFS : Descriptor
Host OS = FAT
Version = 10
Volume Index = 0
Offset = 0


Listing archive: archive_generated_with_java.zip

--
Path = archive_generated_with_java.zip
Type = zip
Physical Size = 220

----------
Path = 
Folder = +
Size = 0
Packed Size = 2
Modified = 2025-08-08 14:22:52
Created = 
Accessed = 
Attributes = D
Encrypted = -
Comment = 
CRC = 
Method = Deflate
Characteristics = Descriptor UTF8
Host OS = FAT
Version = 20
Volume Index = 0
Offset = 0

Path = sub
Folder = +
Size = 0
Packed Size = 2
Modified = 2025-08-08 14:22:52
Created = 
Accessed = 
Attributes = D
Encrypted = -
Comment = 
CRC = 
Method = Deflate
Characteristics = Descriptor UTF8
Host OS = FAT
Version = 20
Volume Index = 0
Offset = 49

Hello @curmas, Aspose.Zip version 24.8 has been released.
It has a new option to compose zip archive without data descriptor for directory entries.
This is how to do it:

var aso  = new ArchiveSaveOptions();
aso.setDataDescriptorPolicy(ZipDataDescriptorPolicy.ForAllFileEntries);
try(Archive z = new Archive()){
    z.createEntries("...");
    z.save("folder_without_data_desc.zip", aso);
}

This code composes an archive that can be extracted with Java ZipInputStream.

try (ZipInputStream zin = new ZipInputStream(new FileInputStream("folder_without_data_desc.zip"))) 
{
    ZipEntry entry;
    while ((entry = zin.getNextEntry()) != null) {        
        System.out.println(entry.getName());
    }
}

ZipDataDescriptorPolicy.ForAllFileEntries is not applicable to encrypted zip archives. In general, please use it only when composing archives that need to be compatible with ZipInputStream.
By the way, you may find this AI-generated report on ZipInputStream interesting.