Skip to content

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:

Terminal window
$ zpack verify damaged.zpak
zpack: 'damaged.zpak' failed verification: HashMismatch

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

The broadest of them. It means the index describes something the file cannot support:

  • The index is truncated - the file ends mid-record
  • entry_count is larger than the file could possibly hold
  • An entry’s offset lands inside the index, or past end of file
  • offset + stored_size overflows u64
  • size is larger than stored_size could ever inflate to (the decompression-bomb bound)
  • A store entry whose stored_size differs from its size
  • From read or unpack: an entry produced fewer or more bytes than the index promised, or a malformed deflate stream
  • From writeManifest: the entry sizes sum past u64
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.

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.

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.

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.

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 fail

Treat 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 });