BookStackApp/BookStack · error · NotFoundException

errors.chapter_not_found

Error message

errors.chapter_not_found

What it means

ChapterQueries::findVisibleBySlugsOrFail looks up a chapter by its parent book slug and chapter slug, restricted to entities visible to the current user. If no matching chapter row exists (or the user lacks view permission, filtering it out), it throws a NotFoundException with the translated 'errors.chapter_not_found' message. This is BookStack's standard 'entity not found or not visible' 404 for chapter slug lookups.

Source

Thrown at app/Entities/Queries/ChapterQueries.php:47

    public function findVisibleByIdOrFail(int $id): Chapter
    {
        return $this->start()->scopes('visible')->findOrFail($id);
    }

    public function findVisibleBySlugsOrFail(string $bookSlug, string $chapterSlug): Chapter
    {
        /** @var ?Chapter $chapter */
        $chapter = $this->start()
            ->scopes('visible')
            ->with('book')
            ->whereHas('book', function (Builder $query) use ($bookSlug) {
                $query->where('slug', '=', $bookSlug);
            })
            ->where('slug', '=', $chapterSlug)
            ->first();

        if (is_null($chapter)) {
            throw new NotFoundException(trans('errors.chapter_not_found'));
        }

        return $chapter;
    }

    public function usingSlugs(string $bookSlug, string $chapterSlug): Builder
    {
        return $this->start()
            ->where('slug', '=', $chapterSlug)
            ->whereHas('book', function (Builder $query) use ($bookSlug) {
                $query->where('slug', '=', $bookSlug);
            });
    }

    public function visibleForList(): Builder
    {
        return $this->start()
            ->scopes('visible')

View on GitHub (pinned to 18f8469a1c)

Solutions

  1. Verify the book and chapter slugs in the URL/API call match the current entity slugs (check from the chapter's page URL).
  2. Confirm the chapter is not deleted (check the trash) and re-restore if needed.
  3. Check that the acting user/role has 'View' permission on the book/chapter; grant via role permissions or shelve/book restrictions.
  4. If doing lookups in code, prefer findVisibleBySlugsOrFail only after validating slugs, or catch NotFoundException and return a friendly 404.

Example fix

// before
$chapter = $chapterQueries->findVisibleBySlugsOrFail($oldBookSlug, $chapterSlug);
// after
try {
    $chapter = $chapterQueries->findVisibleBySlugsOrFail($bookSlug, $chapterSlug);
} catch (NotFoundException $e) {
    abort(404, trans('errors.chapter_not_found'));
}
Defensive patterns

Strategy: try-catch

Validate before calling

$chapter = Chapter::query()->where('slug', $chapterSlug)
    ->whereHas('book', fn($q) => $q->where('slug', $bookSlug))->first();
if (!$chapter) { /* handle missing before calling */ }

Type guard

function isChapter(?Chapter $c): bool { return $c !== null; }

Try / catch

try {
    $chapter = $chapterQueries->findVisibleBySlugsOrFail($bookSlug, $chapterSlug);
} catch (\BookStack\Exceptions\NotFoundException $e) {
    abort(404, trans('errors.chapter_not_found'));
}

Prevention

When it happens

Trigger: Calling findVisibleBySlugsOrFail($bookSlug, $chapterSlug) when: the book slug is wrong/renamed; the chapter slug is wrong or the chapter was renamed; the chapter is in the trash (soft-deleted); or the chapter/book exists but the current user has no view permission, so the visibility query returns null.

Common situations: Stale links or bookmarks after a book/chapter rename (slugs auto-change from titles); API clients caching old slugs; permission-restricted chapters appearing as 404 rather than 403 to users without access; referencing a chapter from another instance/environment.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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