Errors
zpack returns Zig error values, never error codes or sentinels. The CLI prints the error name verbatim, so every message maps onto a row below:
$ zpack verify damaged.zpakzpack: 'damaged.zpak' failed verification: HashMismatchFormat errors
Section titled “Format errors”zpack.format.Error - structural problems with an archive. All but
AssetIdCollision and PathConflict come from reading the index itself.
| Error | Cause | Returned by |
|---|---|---|
BadMagic |
The file does not start with ZPAK, including a file shorter than four bytes |
Archive.open |
UnsupportedVersion |
The version field is not 1. See compatibility |
Archive.open |
UnsupportedMethod |
An entry’s method byte is neither 0 nor 1 |
Archive.open |
CorruptArchive |
Several structural problems - see below | Archive.open, read, unpack, writeManifest |
InvalidPath |
A path that is empty, has an empty or ./.. segment, contains \, :, or NUL, or is not valid UTF-8 |
Archive.open, pack |
PathTooLong |
A path longer than 65535 bytes | Archive.open, pack |
DuplicatePath |
The same path appears twice | Archive.open, pack |
PathConflict |
One path is a directory prefix of another, so both cannot exist at once | Archive.open |
AssetIdCollision |
Two different paths hash to the same asset id | Archive.open, pack |
CorruptArchive in detail
Section titled “CorruptArchive in detail”The broadest of them. It means the index describes something the file cannot support:
- The index is truncated - the file ends mid-record
entry_countis larger than the file could possibly hold- An entry’s
offsetlands inside the index, or past end of file offset + stored_sizeoverflowsu64sizeis larger thanstored_sizecould ever inflate to (the decompression-bomb bound)- A
storeentry whosestored_sizediffers from itssize - From
readorunpack: an entry produced fewer or more bytes than the index promised, or a malformed deflate stream - From
writeManifest: the entry sizes sum pastu64
Content errors
Section titled “Content errors”| Error | Cause | Returned by |
|---|---|---|
HashMismatch |
The bytes do not match the hash recorded at pack time, or the entry’s length differs from its declared size | Archive.read, readAlloc, verify, unpack |
Never returned by Archive.open, which does not read contents.
entryReader never returns it either - it verifies
nothing.
Buffer and lookup errors
Section titled “Buffer and lookup errors”| Error | Cause | Returned by |
|---|---|---|
BufferTooSmall |
buffer.len < entry.size; or a buffer under stream_buffer_len for a deflated entry; or entry.size exceeds usize on a 32-bit target |
Archive.read, entryReader |
FileNotFound |
The path is not in the archive | Archive.readAlloc |
OutOfMemory |
Allocation failed, or entry.size exceeds usize |
Archive.open, readAlloc, pack |
FileNotFound from readAlloc means a missing entry. The same error from
Archive.open or pack comes from the filesystem and means a missing file.
find returns null rather than an error for a missing path.
Pack errors
Section titled “Pack errors”| Error | Cause | Returned by |
|---|---|---|
TooManyFiles |
More than maxInt(u32) files in the tree |
pack |
TooManyRules |
More than 1024 rules in .zpackignore |
pack, Ignore.parse, Ignore.load |
SourceChanged |
A file’s length changed between being compressed and being re-read for the store fallback | pack |
SourceChanged means something wrote to a source file mid-pack. The archive is
abandoned rather than completed with an entry whose length cannot be trusted -
and because pack is atomic, any existing archive is left untouched.
Errors from the standard library
Section titled “Errors from the standard library”Beyond zpack’s own, calls propagate whatever std.Io returns:
| Kind | Examples |
|---|---|
| Filesystem | FileNotFound, AccessDenied, IsDir, NotDir, NoSpaceLeft |
| Read | ReadFailed, EndOfStream |
| Write | WriteFailed |
| Allocator | OutOfMemory |
error.ReadFailed from a StoredReader means the
underlying positional read failed; the cause is kept in the reader’s err
field.
Handling patterns
Section titled “Handling patterns”Distinguish “not there” from “broken”:
const entry = archive.find(path) orelse { // Not in the archive. Not an error condition on its own. return null;};const bytes = try archive.read(entry, buffer); // this can genuinely failTreat a missing ignore file as normal:
// Returns `Ignore.empty` rather than erroring when there is no ignore file.var ignore = try zpack.Ignore.load(gpa, io, dir, ".zpackignore");Verify once at startup, then stream freely:
archive.verify() catch |err| switch (err) { error.HashMismatch => { std.log.err("assets are damaged; reinstall", .{}); return err; }, else => return err,};Report the error name, since it maps to this page:
std.log.err("cannot open archive '{s}': {t}", .{ path, err });