Kareadita/Kavita · error · KavitaException
bookmark-dir-permissions
bookmark-dir-permissions
Error message
bookmark-dir-permissions
What it means
Thrown by SettingsService when updating ServerSettingKey.BookmarkDirectory and directoryService.CheckWriteAccess(bookmarkDirectory) returns false. Kavita writes user bookmarks (saved pages) into this directory, so it must be writable by the process; the guard fails fast rather than silently dropping bookmarks later.
Source
Thrown at Kavita.Services/SettingsService.cs:421
((int)updateSettingsDto.PdfRenderResolution).ToString() != setting.Value)
{
setting.Value = ((int)updateSettingsDto.PdfRenderResolution).ToString();
unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.HostName && updateSettingsDto.HostName + string.Empty != setting.Value)
{
setting.Value = (updateSettingsDto.HostName + string.Empty).Trim();
setting.Value = UrlHelper.RemoveEndingSlash(setting.Value);
unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.BookmarkDirectory && bookmarkDirectory != setting.Value)
{
// Validate new directory can be used
if (!await directoryService.CheckWriteAccess(bookmarkDirectory))
{
throw new KavitaException("bookmark-dir-permissions");
}
originalBookmarkDirectory = setting.Value;
// Normalize the path deliminators. Just to look nice in DB, no functionality
setting.Value = directoryService.FileSystem.Path.GetFullPath(bookmarkDirectory);
unitOfWork.SettingsRepository.Update(setting);
updateBookmarks = true;
}
if (setting.Key == ServerSettingKey.AllowStatCollection &&
updateSettingsDto.AllowStatCollection + string.Empty != setting.Value)
{
setting.Value = updateSettingsDto.AllowStatCollection + string.Empty;
unitOfWork.SettingsRepository.Update(setting);
}
View on GitHub (pinned to 9c3e540000)
Solutions
- Ensure the directory exists and the Kavita process user has write permission (chmod/chown on Linux).
- For Docker, mount the bookmark volume read-write (drop ':ro').
- Pick a directory inside the existing writable data directory.
- Run CheckWriteAccess manually with the Kavita user to confirm permissions before saving.
Example fix
// before updateSettingsDto.BookmarkDirectory = "/mnt/readonly/bookmarks"; await settingsService.UpdateSettings(updateSettingsDto); // after sudo mkdir -p /var/lib/kavita/bookmarks && sudo chown kavita:kavita /var/lib/kavita/bookmarks updateSettingsDto.BookmarkDirectory = "/var/lib/kavita/bookmarks"; await settingsService.UpdateSettings(updateSettingsDto);
Defensive patterns
Strategy: validation
Validate before calling
if (!await directoryService.CheckWriteAccess(bookmarkDirectory))
return BadRequest("bookmark-dir-permissions");
updateSettingsDto.BookmarkDirectory = bookmarkDirectory;
await settingsService.UpdateSettings(updateSettingsDto); Type guard
static async Task<bool> DirectoryIsWritable(string path, IDirectoryService ds) => await ds.CheckWriteAccess(path);
Prevention
- Ensure the directory exists and is writable by the Kavita process user.
- Mount Docker volumes read-write (drop ':ro').
- Prefer a path inside the existing writable data directory.
- Verify with CheckWriteAccess before saving.
When it happens
Trigger: Saving server settings with a BookmarkDirectory that the Kavita process cannot write to - missing directory, read-only mount, insufficient filesystem permissions, or an invalid path.
Common situations: Docker volume mounted read-only; SELinux/AppArmor denying writes; bookmark path on a network share without write perms; non-existent directory that CheckWriteAccess doesn't auto-create; or path with a typo.
Related errors
- ip-address-invalid
- bad-copy-files-for-download
- generic-create-temp-archive
- {archivePath} does not exist on disk
- file-doesnt-exist
AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13).
Data as JSON: /api/errors/08ffdd39aae01a10.
Report an issue: GitHub.