BookStackApp/BookStack · error · ZipExportException

errors.import_zip_cant_decode_data

Error message

errors.import_zip_cant_decode_data

What it means

BookStack's ZIP import reader throws ZipExportException with the localized message 'errors.import_zip_cant_decode_data' when the uploaded ZIP archive does not contain a 'data.json' entry at its root. ZipExportReader::readData() calls $this->zip->statName('data.json') and treats a false result as an unreadable/invalid export. This is the reader's way of rejecting archives that are not valid BookStack ZIP exports.

Source

Thrown at app/Exports/ZipExports/ZipExportReader.php:63

    public function close(): void
    {
        if ($this->open) {
            $this->zip->close();
            $this->open = false;
        }
    }

    /**
     * @throws ZipExportException
     */
    public function readData(): array
    {
        $this->open();

        $info = $this->zip->statName('data.json');
        if ($info === false) {
            throw new ZipExportException(trans('errors.import_zip_cant_decode_data'));
        }

        $maxSize = max(intval(config()->get('app.upload_limit')), 1) * 1000000;
        if ($info['size'] > $maxSize) {
            throw new ZipExportException(trans('errors.import_zip_data_too_large'));
        }

        // Validate json data exists, including metadata
        $jsonData = $this->zip->getFromName('data.json') ?: '';
        $importData = json_decode($jsonData, true);
        if (!$importData) {
            throw new ZipExportException(trans('errors.import_zip_cant_decode_data'));
        }

        return $importData;
    }

    public function fileExists(string $fileName): bool

View on GitHub (pinned to 18f8469a1c)

Solutions

  1. Verify the ZIP contains a root-level data.json (unzip -l export.zip).
  2. Re-zip so data.json sits at the archive root, not inside a nested directory.
  3. Regenerate the export from the source BookStack instance instead of hand-editing the archive.
  4. Check the upload wasn't truncated/corrupted (compare file size/checksum).

Example fix

// before (importing a zip where data.json is nested)
zip: my-export.zip -> my-export/data.json
// after
zip: my-export.zip -> data.json
Defensive patterns

Strategy: validation

Validate before calling

$zip = new ZipArchive();
if ($zip->open($path) === true) {
    if ($zip->locateName('data.json', ZipArchive::FL_NODIR) === false) {
        throw new \InvalidArgumentException('ZIP is not a BookStack export: missing data.json at root');
    }
}
$zip->close();

Type guard

function isBookStackExportZip(string $path): bool {
    $zip = new ZipArchive();
    if ($zip->open($path) !== true) return false;
    $ok = $zip->locateName('data.json', ZipArchive::FL_NODIR) !== false;
    $zip->close();
    return $ok;
}

Try / catch

try {
    $model = $reader->decodeDataToExportModel();
} catch (\BookStack\Exports\ZipExports\ZipExportException $e) {
    if (trans('errors.import_zip_cant_decode_data') === $e->getMessage()) {
        // report invalid archive to the user
    }
}

Prevention

When it happens

Trigger: Importing a ZIP that has no data.json at the root (e.g. a plain file archive, an export re-zipped so data.json ended up in a subfolder, or a truncated/corrupt upload where the central directory lost the entry).

Common situations: Users re-compress exported files with Finder/Explorer nesting a folder inside the zip; partially uploaded archives; renaming .zip exports; attempting to import a BookStack v5-style zip into an older import path.

Related errors


AI-assisted analysis of BookStackApp/BookStack@18f8469a1c (2026-09-02). Data as JSON: /api/errors/13f152c5f4d63502. Report an issue: GitHub.