{"record":{"id":"b85ae3e7a781c524","repo":"BookStackApp/BookStack","slug":"errors-path-not-writable","errorCode":null,"errorMessage":"errors.path_not_writable","messagePattern":"errors\\.path_not_writable","errorType":"exception","errorClass":"FileUploadException","httpStatus":null,"severity":"error","filePath":"app/Uploads/FileStorage.php","lineNumber":67,"sourceCode":"    public function uploadFile(UploadedFile $file, string $subDirectory, string $suffix, string $extension): string\n    {\n        $storage = $this->getStorageDisk();\n        $basePath = trim($subDirectory, '/') . '/';\n\n        $uploadFileName = Str::random(16) . ($suffix ? \"-{$suffix}\" : '') . ($extension ? \".{$extension}\" : '');\n        while ($storage->exists($this->adjustPathForStorageDisk($basePath . $uploadFileName))) {\n            $uploadFileName = Str::random(3) . $uploadFileName;\n        }\n\n        $fileStream = fopen($file->getRealPath(), 'r');\n        $filePath = $basePath . $uploadFileName;\n\n        try {\n            $storage->writeStream($this->adjustPathForStorageDisk($filePath), $fileStream);\n        } catch (Exception $e) {\n            Log::error('Error when attempting file upload:' . $e->getMessage());\n\n            throw new FileUploadException(trans('errors.path_not_writable', ['filePath' => $filePath]));\n        }\n\n        return $filePath;\n    }\n\n    /**\n     * Check whether the configured storage is remote from the host of this app.\n     */\n    public function isRemote(): bool\n    {\n        return $this->getStorageDiskName() === 's3';\n    }\n\n    /**\n     * Get the actual path on system for the given relative file path.\n     */\n    public function getSystemPath(string $filePath): string\n    {","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/BookStackApp/BookStack/blob/18f8469a1c72f8cc8497e9372635e6dea5028071/app/Uploads/FileStorage.php#L49-L85","documentation":"FileUploadException with 'errors.path_not_writable' is thrown by FileStorage::uploadFile when the underlying storage disk's writeStream() call fails while saving an uploaded file at $filePath. It wraps any filesystem exception (disk full, permissions, missing directory, S3 errors) into a user-facing localized message naming the target path.","triggerScenarios":"Calling uploadFile() during file uploads when writeStream() throws: directory not writable by PHP/web user, disk quota exceeded, misconfigured storage disk credentials (s3/local path), or invalid/missing stream resource.","commonSituations":"Web server user lacks write permission on the uploads directory; local storage path wrong after moving servers or changing FILESYSTEM_DISK; S3 keys/bucket misconfigured; disk full on self-hosted instances; SELinux blocking writes.","solutions":["Check the Laravel log for the wrapped exception message ('Error when attempting file upload: ...') to find the root cause","Verify the storage directory exists and is writable by the PHP process user (chown/chmod, e.g. chmod -R 775 storage)","Confirm the storage disk config (config/filesystems.php, FILESYSTEM_DISK env) points to a valid, correctly-credentialed disk","Check free disk space and quota on the storage target","For cloud disks, validate credentials/bucket/region and connectivity"],"exampleFix":"// before (root cause example: wrong local root)\n'root' => storage_path('app/old-uploads'),\n// after\n'root' => storage_path('app/uploads'),\n// then: sudo chown -R www-data:www-data storage/app/uploads && chmod -R 775 storage/app/uploads","handlingStrategy":"try-catch","validationCode":"// before upload\n$path = storage_path('app/uploads');\nif (!is_dir($path) || !is_writable($path)) {\n    throw new \\RuntimeException(\"Storage path not writable: $path\");\n}\nif (disk_free_space($path) < $file->getSize()) {\n    throw new \\RuntimeException('Insufficient disk space');\n}","typeGuard":null,"tryCatchPattern":"try {\n    $stored = $fileStorage->uploadFile($file, $name);\n} catch (FileUploadException $e) {\n    Log::error('Upload failed: ' . $e->getMessage());\n    return back()->withErrors(['file' => 'Storage is not writable; contact the administrator.']);\n}","preventionTips":["Provision storage directories with correct ownership/permissions in deployment scripts (chown www-data, chmod 775)","Monitor disk free space and quotas with alerting","Test the configured storage disk with a smoke-test write during health checks","Keep FILESYSTEM_DISK and disk credentials in validated env config"],"tags":["php","laravel","file-upload","filesystem","permissions"],"backgroundTag":"path-not-writable","analyzedSha":"18f8469a1c72f8cc8497e9372635e6dea5028071","analyzedAt":"2026-09-02T19:49:33.068Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}