BookStackApp/BookStack · error · PermissionsException
This page is already published or does not belong to you.
Error message
This page is already published or does not belong to you.
What it means
PageController::ensureDraftAccess throws PermissionsException('This page is already published or does not belong to you.') when a draft page operation targets a page that either is no longer a draft ($draft->draft is false) or was created by a different user ($draft->created_by !== user()->id). Draft pages in BookStack are private to their creator until published, so other users (or actions on a since-published page) may not edit/delete them via draft endpoints.
Source
Thrown at app/Entities/Controllers/PageController.php:487
return redirect($page->getUrl('/copy'));
}
$this->checkOwnablePermission(Permission::PageCreate, $newParent);
$newName = $request->input('name') ?: $page->name;
$pageCopy = $cloner->clonePage($page, $newParent, $newName);
$this->showSuccessNotification(trans('entities.pages_copy_success'));
return redirect($pageCopy->getUrl());
}
/**
* @throws PermissionsException
*/
protected function ensureDraftAccess(Page $draft): void
{
if (!$draft->draft || $draft->created_by !== user()->id) {
throw new PermissionsException('This page is already published or does not belong to you.');
}
}
}
View on GitHub (pinned to 18f8469a1c)
Solutions
- Check the page is still a draft before calling draft endpoints (page 'draft' flag true) and use the normal page-update endpoint once published
- Only the draft creator should perform draft edits/deletes; if collaboration is needed, publish the page and use standard page permissions
- Refresh the draft id from the API after publishing, since draft endpoints no longer apply
- Handle the PermissionsException in clients and re-fetch the page to get its current state
Example fix
// before
$pages->updateDraft($pageId, $data); // page may already be published
// after
$page = $pages->details($pageId);
if ($page['draft']) { $pages->updateDraft($pageId, $data); }
else { $pages->update($pageId, $data); } Defensive patterns
Strategy: type-guard
Validate before calling
// Fetch the page first and verify it is still your draft
$page = $api->get("/api/pages/{$id}")->json();
if ($page['draft'] === false || $page['created_by'] !== $myUserId) {
throw new RuntimeException('Page is published or owned by someone else; use normal page endpoints');
} Type guard
function isEditableDraft(array $page, int $myUserId): bool {
return !empty($page['draft']) && (int) $page['created_by'] === $myUserId;
} Try / catch
try {
$api->put("/api/pages/{$id}/draft", $data);
} catch (ClientException $e) {
if ($e->getResponse()->getStatusCode() === 403 || $e->getResponse()->getStatusCode() === 404) {
// re-fetch page: if published, switch to standard update endpoint
}
throw $e;
} Prevention
- Re-fetch page state before each draft mutation instead of caching ids
- Switch to standard page update endpoints as soon as the page is published
- Remember drafts are single-owner; use published pages for collaboration
- Handle stale-draft races in multi-tab or multi-user workflows
When it happens
Trigger: Calling editDraft/saveDraft/destroyDraft/store(revision) on a page that was already published (draft flag cleared); one user attempting to modify another user's draft by id; a stale client holding a draft id that has since been published; two users racing to edit the same draft.
Common situations: Scripts caching draft ids across long runs; collaborators expecting shared drafts (BookStack drafts are single-owner); a draft published in another tab while an edit form is still open.
Related errors
- errors.api_user_no_api_permission
- errors.chapter_not_found
- errors.page_not_found
- User does not have permission to create a chapter within the
- User does not have permission to create a page within the ne
AI-assisted analysis of BookStackApp/BookStack@18f8469a1c (2026-09-02).
Data as JSON: /api/errors/0b4bcc93e8579ee3.
Report an issue: GitHub.