diff --git a/apps/server/src/services/data_dir.ts b/apps/server/src/services/data_dir.ts index 4f277736b..1e6de81bf 100644 --- a/apps/server/src/services/data_dir.ts +++ b/apps/server/src/services/data_dir.ts @@ -75,9 +75,45 @@ export function getPlatformAppDataDir(platform: ReturnType, } } +function outputPermissionDiagnostics(targetPath: fs.PathLike) { + const pathStr = targetPath.toString(); + const parentDir = pathJoin(pathStr, ".."); + + console.error("\n========== PERMISSION ERROR DIAGNOSTICS =========="); + console.error(`Failed to create directory: ${pathStr}`); + + // Output current process UID:GID (Unix only) + if (typeof process.getuid === "function" && typeof process.getgid === "function") { + console.error(`Process running as UID:GID = ${process.getuid()}:${process.getgid()}`); + } + + // Try to get parent directory stats + try { + const stats = fs.statSync(parentDir); + console.error(`Parent directory: ${parentDir}`); + console.error(` Owner UID:GID = ${stats.uid}:${stats.gid}`); + console.error(` Permissions = ${(stats.mode & 0o777).toString(8)} (octal)`); + } catch { + console.error(`Parent directory ${parentDir} is not accessible`); + } + + console.error("\nTo fix this issue:"); + console.error(" - Ensure the data directory is owned by the user running Trilium"); + console.error(" - Or set USER_UID and USER_GID environment variables to match the directory owner"); + console.error(" - Example: docker run -e USER_UID=$(id -u) -e USER_GID=$(id -g) ..."); + console.error("====================================================\n"); +} + function createDirIfNotExisting(path: fs.PathLike, permissionMode: fs.Mode = FOLDER_PERMISSIONS) { if (!fs.existsSync(path)) { - fs.mkdirSync(path, permissionMode); + try { + fs.mkdirSync(path, permissionMode); + } catch (err: unknown) { + if (err && typeof err === "object" && "code" in err && err.code === "EACCES") { + outputPermissionDiagnostics(path); + } + throw err; + } } }