BookStackApp/BookStack · error · ZipImportException

Parent book required for chapter import.

Error message

Parent book required for chapter import.

What it means

ZipImportRunner::run() requires that a chapter export (ZipExportChapter) is imported with a parent that is a Book instance. If $parent is null or any other entity type, it throws ZipImportException 'Parent book required for chapter import.' Chapters can only live directly under books in BookStack's hierarchy.

Source

Thrown at app/Exports/ZipExports/ZipImportRunner.php:74

        $errors = (new ZipExportValidator($reader))->validate();
        if ($errors) {
            throw new ZipImportException([
                trans('errors.import_validation_failed'),
                ...$errors,
            ]);
        }

        try {
            $exportModel = $reader->decodeDataToExportModel();
        } catch (ZipExportException $e) {
            throw new ZipImportException([$e->getMessage()]);
        }

        // Validate parent type
        if ($exportModel instanceof ZipExportBook && ($parent !== null)) {
            throw new ZipImportException(["Must not have a parent set for a Book import."]);
        } else if ($exportModel instanceof ZipExportChapter && !($parent instanceof Book)) {
            throw new ZipImportException(["Parent book required for chapter import."]);
        } else if ($exportModel instanceof ZipExportPage && !($parent instanceof Book || $parent instanceof Chapter)) {
            throw new ZipImportException(["Parent book or chapter required for page import."]);
        }

        $this->ensurePermissionsPermitImport($exportModel, $parent);

        if ($exportModel instanceof ZipExportBook) {
            $entity = $this->importBook($exportModel, $reader);
        } else if ($exportModel instanceof ZipExportChapter) {
            $entity = $this->importChapter($exportModel, $parent, $reader);
        } else {
            $entity = $this->importPage($exportModel, $parent, $reader);
        }

        $this->references->replaceReferences();

        $reader->close();
        $this->cleanup();

View on GitHub (pinned to 18f8469a1c)

Solutions

  1. Pass a valid Book id as parent_id in the import API request.
  2. Select a Book as the parent in the import form.
  3. Fetch the correct book id (e.g. via the search/API) before running the import.

Example fix

// before
POST /import {"zip_id": 7}
// after
POST /import {"zip_id": 7, "parent_id": 12} // 12 = a Book id
Defensive patterns

Strategy: validation

Validate before calling

$data = json_decode($zip->getFromName('data.json') ?: '', true);
if (isset($data['chapter']) && (!$parent instanceof \BookStack\Entities\Models\Book)) {
    throw new \InvalidArgumentException('Chapter imports require a Book parent');
}

Type guard

function chapterParentOk($parent): bool {
    return $parent instanceof \BookStack\Entities\Models\Book;
}

Try / catch

try {
    $runner->run($import, $parent);
} catch (\BookStack\Exceptions\ZipImportException $e) {
    // resolve a Book id and retry the import
}

Prevention

When it happens

Trigger: Importing a chapter ZIP with no parent selected, or with a Chapter/Page/Shelf passed as parent.

Common situations: API scripts forgetting parent_id for chapter imports; selecting the wrong parent in the import UI; automation that treats chapters like books.

Related errors


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