{"record":{"id":"722512caf6282ebf","repo":"BookStackApp/BookStack","slug":"errors-page-not-found","errorCode":null,"errorMessage":"errors.page_not_found","messagePattern":"errors\\.page_not_found","errorType":"exception","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"app/Entities/Queries/PageQueries.php","lineNumber":42,"sourceCode":"    /**\n     * @return Builder<Page>\n     */\n    public function start(): Builder\n    {\n        return Page::query();\n    }\n\n    public function findVisibleById(int $id): ?Page\n    {\n        return $this->start()->scopes('visible')->find($id);\n    }\n\n    public function findVisibleByIdOrFail(int $id): Page\n    {\n        $page = $this->findVisibleById($id);\n\n        if (is_null($page)) {\n            throw new NotFoundException(trans('errors.page_not_found'));\n        }\n\n        return $page;\n    }\n\n    public function findVisibleBySlugsOrFail(string $bookSlug, string $pageSlug): Page\n    {\n        /** @var ?Page $page */\n        $page = $this->start()->with('book')\n            ->scopes('visible')\n            ->whereHas('book', function (Builder $query) use ($bookSlug) {\n                $query->where('slug', '=', $bookSlug);\n            })\n            ->where('slug', '=', $pageSlug)\n            ->first();\n\n        if (is_null($page)) {\n            throw new NotFoundException(trans('errors.page_not_found'));","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/BookStackApp/BookStack/blob/18f8469a1c72f8cc8497e9372635e6dea5028071/app/Entities/Queries/PageQueries.php#L24-L60","documentation":"PageQueries::findVisibleByIdOrFail fetches a page by ID through the visibility-restricted findVisibleById query. When the query returns null — page absent, soft-deleted, or invisible to the current user — it throws NotFoundException with 'errors.page_not_found'. It is the fail-fast wrapper converting 'no visible row' into a 404 exception.","triggerScenarios":"Calling findVisibleByIdOrFail($id) with an ID that doesn't exist, references a soft-deleted (trashed) page, or a page the current user cannot view due to role/restriction permissions.","commonSituations":"API integrations holding stale page IDs after deletion; deep links to pages removed during book reorganization; users without view permissions receiving 404 instead of 403; importing content into the wrong instance.","solutions":["Confirm the page ID exists and is not in the trash (Page::withTrashed()->find($id) locally or check the Trash screen).","Verify the user's role has view access or entity-level restrictions allowing the page.","Catch NotFoundException around the call and handle missing pages gracefully.","If the page was moved, its ID persists — check the URL/slug rather than recreating content."],"exampleFix":"// before\n$page = $pageQueries->findVisibleByIdOrFail($id);\n// after\ntry {\n    $page = $pageQueries->findVisibleByIdOrFail($id);\n} catch (NotFoundException $e) {\n    Log::warning('Page not visible', ['id' => $id]);\n    abort(404);\n}","handlingStrategy":"try-catch","validationCode":"if (!\\BookStack\\Entities\\Page::where('id', $id)->exists()) {\n    throw new \\InvalidArgumentException(\"Page {$id} does not exist\");\n}","typeGuard":"function pageIsVisible(\\BookStack\\Entities\\Queries\\PageQueries $q, int $id): bool {\n    return $q->findVisibleById($id) !== null;\n}","tryCatchPattern":"try {\n    $page = $pageQueries->findVisibleByIdOrFail($id);\n} catch (\\BookStack\\Exceptions\\NotFoundException $e) {\n    Log::warning('Page missing/invisible', ['id' => $id]);\n    abort(404);\n}","preventionTips":["Prefer ID lookups over cached IDs that may be stale","Check permissions first if operating as a specific user","Restore from trash instead of recreating content"],"tags":["laravel","not-found","permissions","bookstack"],"backgroundTag":"entity-not-found","analyzedSha":"18f8469a1c72f8cc8497e9372635e6dea5028071","analyzedAt":"2026-09-02T19:49:33.068Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}