The Scenario
You're in the WordPress media uploader, trying to push an image or PDF. The progress bar fills... then nothing. The error message appears:
Upload: Failed to Write File to Disk
No file in the media library. Nothing on disk. Just that message. Here's how to track it down and fix it.
What's Actually Happening
WordPress uploads happen in two distinct steps: PHP writes the file to a temp directory first, then moves it to wp-content/uploads/. Break either step and you get this error. Four things cause it:
- Wrong permissions on
wp-content/uploads/โ the web server user can't write there - PHP temp directory is not writable โ the initial temp write fails before WordPress even tries to move the file
- The uploads directory doesn't exist โ happens regularly after migrations or partial restores
- Disk or inode quota is full โ no space left, nothing gets written
Quick Diagnosis
SSH into the server and run these three checks before changing anything.
1. Check disk space
df -h /var/www/html
At 100% usage, clear space first. Also check inodes โ a directory holding 50,000 small files can exhaust inodes while block space still shows free:
df -i /var/www/html
2. Check the uploads directory
ls -la /var/www/html/wp-content/uploads/
The directory should be owned by your web server user โ www-data on Ubuntu/Debian, apache on CentOS/RHEL โ with write permissions set.
3. Check PHP's temp directory
php -r "echo ini_get('upload_tmp_dir') ?: sys_get_temp_dir();"
Note the path it returns. Confirm that directory is writable by the web server user before moving on.
The Fix
Fix 1: Correct uploads directory permissions (resolves ~90% of cases)
First, identify your actual web server user:
# Ubuntu/Debian
ps aux | grep -E '(apache|nginx|php-fpm)' | grep -v root | head -1
# Or check PHP-FPM pool config
grep -r "user = " /etc/php/*/fpm/pool.d/
Then fix ownership and permissions:
# Replace www-data with your actual web server user
sudo chown -R www-data:www-data /var/www/html/wp-content/uploads/
sudo chmod -R 755 /var/www/html/wp-content/uploads/
On shared hosting where PHP runs as your own user account, 775 is usually the right call:
sudo chmod -R 775 /var/www/html/wp-content/uploads/
Fix 2: Create the uploads directory if it's missing
sudo mkdir -p /var/www/html/wp-content/uploads
sudo chown -R www-data:www-data /var/www/html/wp-content/uploads/
sudo chmod -R 755 /var/www/html/wp-content/uploads/
WordPress can also recreate the directory structure itself. Go to Settings โ Media in wp-admin and click Save โ WordPress will attempt to create the uploads path when it detects it's missing.
Fix 3: Fix PHP temp directory permissions
Uploads directory looks fine but the error persists? The temp write step is likely failing before WordPress even gets to move the file.
# Get the exact temp path PHP is using
php -r "echo ini_get('upload_tmp_dir') ?: sys_get_temp_dir();"
# Fix /tmp if that's what came back
sudo chmod 1777 /tmp
Using a custom temp directory in the PHP-FPM pool config? Fix that path directly:
grep upload_tmp_dir /etc/php/*/fpm/pool.d/*.conf
sudo chown www-data:www-data /path/to/custom/tmp
sudo chmod 755 /path/to/custom/tmp
Fix 4: Enable debug logging to find the exact failing path
Still stuck? Turn on debug logging in wp-config.php temporarily:
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
Attempt the upload again. Then open wp-content/debug.log โ the full PHP error will include the exact file path WordPress was trying to write to, which makes the problem obvious.
CentOS/RHEL: Check SELinux
On CentOS or RHEL, SELinux is often the hidden culprit. Unix permissions look correct, yet writes still fail silently.
# Check if SELinux is enforcing
getenforce
# Restore the correct SELinux context for the uploads directory
sudo restorecon -Rv /var/www/html/wp-content/uploads/
# Or allow the web server to write files broadly
sudo setsebool -P httpd_unified 1
Verify the Fix
- Go to Media โ Add New in wp-admin
- Upload a test image
- Confirm it appears in the media library with a generated thumbnail
- Verify the file landed on disk:
ls -la /var/www/html/wp-content/uploads/$(date +%Y/%m)/
Your file should be there, owned by www-data.
Prevention
When adjusting directory permissions, I use the Unix Permissions Calculator on ToolCraft to verify chmod values before running them โ it shows the exact octal from checkboxes, which is handy when you're second-guessing yourself at 2 AM. Runs in the browser, nothing uploaded.
A disk space monitor in cron will catch quota issues before they cause an outage:
#!/bin/bash
THRESHOLD=85
USAGE=$(df /var/www/html | awk 'NR==2 {print $5}' | sed 's/%//')
if [ "$USAGE" -gt "$THRESHOLD" ]; then
echo "Disk at ${USAGE}% on $(hostname)" | mail -s "[Alert] Disk Space" admin@yourdomain.com
fi
# Add to cron
*/30 * * * * /usr/local/bin/check-disk.sh
One more thing: exclude the uploads directory from any cleanup scripts that sweep old temp files. Aggressive log rotation scripts pointed at the wrong path have wiped entire uploads folders โ it's a painful way to learn that lesson.

