mirror of
https://github.com/BookStackApp/BookStack.git
synced 2026-02-07 11:19:38 +03:00
Race conditions lead to errors for content permission generation #4455
Closed
opened 2026-02-05 08:55:46 +03:00 by OVERLORD
·
10 comments
No Branch/Tag Specified
development
further_theme_development
l10n_development
release
llm_only
vectors
v25-11
docker_env
drawio_rendering
user_permissions
ldap_host_failover
svg_image
prosemirror
captcha_example
fix/video-export
v25.12.3
v25.12.2
v25.12.1
v25.12
v25.11.6
v25.11.5
v25.11.4
v24.11.4
v25.11.3
v25.11.2
v25.11.1
v25.11
v25.07.3
v25.07.2
v25.07.1
v25.07
v25.05.2
v25.05.1
v25.05
v25.02.5
v25.02.4
v25.02.3
v25.02.2
v25.02.1
v25.02
v24.12.1
v24.12
v24.10.3
v24.10.2
v24.10.1
v24.10
v24.05.4
v24.05.3
v24.05.2
v24.05.1
v24.05
v24.02.3
v24.02.2
v24.02.1
v24.02
v23.12.3
v23.12.2
v23.12.1
v23.12
v23.10.4
v23.10.3
v23.10.2
v23.10.1
v23.10
v23.08.3
v23.08.2
v23.08.1
v23.08
v23.06.2
v23.06.1
v23.06
v23.05.2
v23.05.1
v23.05
v23.02.3
v23.02.2
v23.02.1
v23.02
v23.01.1
v23.01
v22.11.1
v22.11
v22.10.2
v22.10.1
v22.10
v22.09.1
v22.09
v22.07.3
v22.07.2
v22.07.1
v22.07
v22.06.2
v22.06.1
v22.06
v22.04.2
v22.04.1
v22.04
v22.03.1
v22.03
v22.02.3
v22.02.2
v22.02.1
v22.02
v21.12.5
v21.12.4
v21.12.3
v21.12.2
v21.12.1
v21.12
v21.11.3
v21.11.2
v21.11.1
v21.11
v21.10.3
v21.10.2
v21.10.1
v21.10
v21.08.6
v21.08.5
v21.08.4
v21.08.3
v21.08.2
v21.08.1
v21.08
v21.05.4
v21.05.3
v21.05.2
v21.05.1
v21.05
v21.04.6
v21.04.5
v21.04.4
v21.04.3
v21.04.2
v21.04.1
v21.04
v0.31.8
v0.31.7
v0.31.6
v0.31.5
v0.31.4
v0.31.3
v0.31.2
v0.31.1
v0.31.0
v0.30.7
v0.30.6
v0.30.5
v0.30.4
v0.30.3
v0.30.2
v0.30.1
v0.30.0
v0.29.3
v0.29.2
v0.29.1
v0.29.0
v0.28.3
v0.28.2
v0.28.1
v0.28.0
v0.27.5
v0.27.4
v0.27.3
v0.27.2
v0.27.1
v0.27
v0.26.4
v0.26.3
v0.26.2
v0.26.1
v0.26.0
v0.25.5
v0.25.4
v0.25.3
v0.25.2
v0.25.1
v0.25.0
v0.24.3
v0.24.2
v0.24.1
v0.24.0
v0.23.2
v0.23.1
v0.23.0
v0.22.0
v0.21.0
v0.20.3
v0.20.2
v0.20.1
v0.20.0
v0.19.0
v0.18.5
v0.18.4
v0.18.3
v0.18.2
v0.18.1
v0.18.0
v0.17.4
v0.17.3
v0.17.2
v0.17.1
v0.17.0
v0.16.3
v0.16.2
v0.16.1
v0.16.0
v0.15.3
v0.15.2
v0.15.1
v0.15.0
v0.14.3
v0.14.2
v0.14.1
v0.14.0
v0.13.1
v0.13.0
v0.12.2
v0.12.1
v0.12.0
v0.11.2
v0.11.1
v0.11.0
v0.10.0
v0.9.3
v0.9.2
v0.9.1
v0.9.0
v0.8.2
v0.8.1
v0.8.0
v0.7.6
v0.7.5
v0.7.4
v0.7.3
0.7.2
v.0.7.1
v0.7.0
v0.6.3
v0.6.2
v0.6.1
v0.6.0
v0.5.0
Labels
Clear labels
🎨 Design
📖 Docs Update
🐛 Bug
🐛 Bug
:cat2:🐈 Possible duplicate
💿 Database
☕ Open to discussion
💻 Front-End
🐕 Support
🚪 Authentication
🌍 Translations
🔌 API Task
🏭 Back-End
⛲ Upstream
🔨 Feature Request
🛠️ Enhancement
🛠️ Enhancement
🛠️ Enhancement
❤️ Happy feedback
🔒 Security
🔍 Pending Validation
💆 UX
📝 WYSIWYG Editor
🌔 Out of scope
🔩 API Request
:octocat: Admin/Meta
🖌️ View Customization
❓ Question
🚀 Priority
🛡️ Blocked
🚚 Export System
♿ A11y
🔧 Maintenance
> Markdown Editor
pull-request
Mirrored from GitHub Pull Request
No Label
🐛 Bug
Milestone
No items
No Milestone
Projects
Clear projects
No project
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: starred/BookStack#4455
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @matthias4217 on GitHub (Feb 12, 2024).
Describe the Bug
To edit pages on Bookstack, some people in our team use the web interface, while others store their content on git and use a Python tool to upload it to Bookstack. In the latter case, this has caused some permission issues, with permissions on the book disappearing (but not on the pages or chapters). The
joint_permissionstable is then empty for the targeted books. Manually creating permissions in this table, or usingphp artisan bookstack:regenerate-permissionsfixes the issue. This has happened three times yet, the first time on January 23rd. It had never happened before we’ve used 23.12. However we are increasingly using Bookstack and the issue could have been present before.It seems similar to https://github.com/BookStackApp/BookStack/issues/4791, but on the book, and not on the page.
Steps to Reproduce
I am not yet sure how the bug is caused exactly. What I can say is that it has always happened while using the API.
Expected Behaviour
The book should remain accessible.
Screenshots or Additional Context
No response
Browser Details
No response
Exact BookStack Version
v23.12
@ssddanbrown commented on GitHub (Feb 12, 2024):
Hi @matthias4217, Could you confirm specifically what API endpoints are being used, and the order they're used in?
Or (if public) link to the tool and advise which methods/actions of the tool are being used?
Just want to gain an idea of exactly what endpoints are used.
@matthias4217 commented on GitHub (Feb 16, 2024):
We have developed two tools around Bookstack. Both are Python apps, in private repositories.
get,putandpostfrom requests.Sessionobject from requests.The error has been detected using Gitplo on the first call to the Bookstack API, a
GETon the books endpoint. I suppose the issue began before that. The three impacted books are edited using Gitplo, and only two of them are managed by Bookstack Carpenter, so I assume it’s a call from Gitplo that is responsible for the issue. These books are notably not modified through the web interface.Gitplo uses these API endpoints :
GET,LIST,DELETE,CREATEGET,LISTGET,LIST,DELETE,CREATE,UPDATEGET,LIST,DELETE,CREATEGET,LIST,DELETE,CREATE,UPDATENotably, it doesn’t modify books nor does it use the Content-permissions endpoint, and apart for three times where this error has happened (on two Bookstack instances in total), our worflow works fine.
@ssddanbrown commented on GitHub (Feb 22, 2024):
Thanks for the extra info @matthias4217.
Can you detail how you're running BookStack? (hosting method, OS, webserver).
@matthias4217 commented on GitHub (Feb 26, 2024):
We run Bookstack on Openshift, and we build our Docker images ourselves (with
php:8.1-fpm-alpineandnginx:1.25-alpine). We have slightly modified the code to show resource ids on pages (using this merge request : https://github.com/BookStackApp/BookStack/pull/4314/files) and tot display the book parent shelves (from this issue : https://github.com/BookStackApp/BookStack/issues/4547#issuecomment-1726420230).@ssddanbrown commented on GitHub (Mar 16, 2024):
Report from a user on discord of similar, running on Ubuntu 18.04 server, with MariaDB 10.1.48 database, Apache2, & PHP8.1-CGI. Reference
@zivillian commented on GitHub (Nov 8, 2024):
We have a similar problem with missing page permission. We are still trying to reproduce, but our assumption is that calling
PUT /api/pages/{id}for multiple pages with changedpriorityin parallel was the root cause (we tried to sort the book).After
php artisan bookstack:regenerate-permissionsthe pages reappeared.System info: BookStack 24.10 on Ubuntu 24.04.1 with MariaDB 10.11.8 and libapache2-mod-php8.3
@zivillian commented on GitHub (Nov 8, 2024):
I was able to reproduce the issue and I think I found the issue. When multiple API requests are running simultaneously there is a race condition. The permissions are first deleted and then recreated:
ac27e18933/app/Permissions/JointPermissionBuilder.php (L146-L151)Delete and Create are each wrapped in transaction:
ac27e18933/app/Permissions/JointPermissionBuilder.php (L163)ac27e18933/app/Permissions/JointPermissionBuilder.php (L228)But two parallel update requests for different pages within the same book may interleave and fail with missing permissions for the second page. Both requests try to update the permissions for the page and the containing book:
ac27e18933/app/Permissions/JointPermissionBuilder.php (L54-L80)Example flow:
Stacktrace:
@ssddanbrown commented on GitHub (Jul 1, 2025):
Another report via #5686.
Thanks for the info @zivillian.
I've assigned this to the next feature release to be addressed.
Needs some careful consideration in regards to the logical order, with consideration to the exact locking/access methods of MySQL, to ensure it's fail-safe and that we won't be rolling back (via transactions) permission changes out of sync with the UI. Right now the deletions are specifically done first in their own transactions to somewhat achieve this. We could regen then delete+insert in one transaction but I need to double check the potential parallel logic.
Could also improve permission rebuild targeting to be more specific (right now it'll re-assess the whole parent chain since that info is needed for assessment during generation) but that's maybe something for a future improvement.
@ssddanbrown commented on GitHub (Jul 7, 2025):
Some changes now prepared in #5689.
These changes wrap the permission-affecting actions as a whole, at a higher level, i transactions.
This naturally provides blocking of edits to the permission store during generation to prevent attempted parallel changes, while also providing roll-back of the entire general action (page creation, permission change etc...) in the event something goes wrong.
I found that the default MySQL "REPEATABLE READ" transaction logic could probably be problematic for BookStack kind of scenarios (since, for example, a later parallel process may end up generating permissions based on old information) so we akwardly go out of the way to set instead use "READ COMMITTED" transactions.
@ssddanbrown commented on GitHub (Jul 9, 2025):
#5689 Has now been merged, to be part of the next feature release, so I will therefore close this off.
Thanks again @zivillian @matthias4217 for your reports and provided detail.