{"record":{"id":"e70a89f8541eed35","repo":"BookStackApp/BookStack","slug":"selected-parent-is-not-a-book-or-chapter","errorCode":null,"errorMessage":"Selected parent is not a book or chapter","messagePattern":"Selected parent is not a book or chapter","errorType":"exception","errorClass":"ZipImportException","httpStatus":null,"severity":"error","filePath":"app/Exports/ImportRepo.php","lineNumber":125,"sourceCode":"\n        $import->path = $path;\n        $import->save();\n\n        Activity::add(ActivityType::IMPORT_CREATE, $import);\n\n        return $import;\n    }\n\n    /**\n     * @throws ZipImportException\n     */\n    public function runImport(Import $import, ?string $parent = null): Entity\n    {\n        $parentModel = null;\n        if ($import->type === 'page' || $import->type === 'chapter') {\n            $parentModel = $parent ? $this->entityQueries->findVisibleByStringIdentifier($parent) : null;\n            if ($parentModel && !($parentModel instanceof Book || $parentModel instanceof Chapter)) {\n                throw new ZipImportException(['Selected parent is not a book or chapter']);\n            }\n        }\n\n        DB::beginTransaction();\n        try {\n            $model = $this->importer->run($import, $parentModel);\n        } catch (ZipImportException $e) {\n            DB::rollBack();\n            $this->importer->revertStoredFiles();\n            throw $e;\n        }\n\n        DB::commit();\n        $this->deleteImport($import);\n        Activity::add(ActivityType::IMPORT_RUN, $import);\n\n        return $model;\n    }","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/BookStackApp/BookStack/blob/18f8469a1c72f8cc8497e9372635e6dea5028071/app/Exports/ImportRepo.php#L107-L143","documentation":"ImportRepo::runImport supports optional parent context for page and chapter imports. If a parent identifier is supplied but resolves to something other than a Book or Chapter, it throws ZipImportException(['Selected parent is not a book or chapter']). This validates import targets before the DB transaction starts.","triggerScenarios":"runImport($import, $parent) where $parent is a Shelf's or Page's ID/slug, a nonexistent identifier, or an entity the importing user cannot view (findVisibleByStringIdentifier returns null so only a truthy non-Book/Chapter triggers... a null parent is treated as no parent).","commonSituations":"Automated import pipelines passing shelf IDs as parents; IDs from a staging instance reused in production; slugs that collide with non-book entities; users lacking visibility of the intended parent so lookup yields null and content imports to root instead.","solutions":["Pass a Book or Chapter ID/slug as the parent (or omit $parent entirely to import at root).","Resolve and type-check the parent before calling runImport.","Ensure the importing user has view permission on the target parent so it resolves.","Catch ZipImportException and read its message list to surface the validation failure to the user."],"exampleFix":"// before\n$importRepo->runImport($import, $shelfSlug); // shelf is invalid\n// after\n$parent = $entityQueries->findVisibleByStringIdentifier($parentId);\nif ($parent instanceof Book || $parent instanceof Chapter) {\n    $importRepo->runImport($import, $parentId);\n} else {\n    $importRepo->runImport($import); // import to root\n}","handlingStrategy":"validation","validationCode":"$parent = $entityQueries->findVisibleByStringIdentifier($parentId);\nif ($parent && !($parent instanceof \\BookStack\\Entities\\Book || $parent instanceof \\BookStack\\Entities\\Chapter)) {\n    throw new \\InvalidArgumentException('Import parent must be a Book or Chapter');\n}","typeGuard":"function validImportParent(?object $e): bool {\n    return $e === null || $e instanceof \\BookStack\\Entities\\Book || $e instanceof \\BookStack\\Entities\\Chapter;\n}","tryCatchPattern":"try {\n    $importRepo->runImport($import, $parentId);\n} catch (\\BookStack\\Exceptions\\ZipImportException $e) {\n    return back()->withErrors(['parent' => implode(', ', $e->getMessages())]);\n}","preventionTips":["Validate the parent identifier resolves to a Book/Chapter before import","Omit the parent to import to root when unsure","Use IDs from the same environment; don't reuse staging identifiers"],"tags":["bookstack","import","validation","laravel"],"backgroundTag":"invalid-parent-entity","analyzedSha":"18f8469a1c72f8cc8497e9372635e6dea5028071","analyzedAt":"2026-09-02T19:49:33.068Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}