"Could Not Copy File." in WordPress Updates: The Path After It Says Which Step Failed
WordPress prints the failing file right after the message. A path inside the archive means extraction into wp-content/upgrade failed; a path in plugins, themes or core means the copy into place did. A full disk is a common cause that does not get its own message during a manual update.
"Could not copy file." means WordPress unpacked or moved an update and the filesystem refused to write one file — and the path printed right after the message tells you which file and which step. Read that path before changing anything. The fix is ownership or free space far more often than file modes.
Where WordPress raises it
The exact string Could not copy file. comes from four places in WordPress 7.2, each with its own error code:
| Error code | Function | Step |
|---|---|---|
copy_failed_ziparchive |
_unzip_file_ziparchive() |
Writing an extracted file into wp-content/upgrade/ |
copy_failed_pclzip |
_unzip_file_pclzip() |
The same, when the ZipArchive extension is missing |
copy_failed_copy_dir |
copy_dir() |
Copying the unpacked file into its final place |
copy_failed_for_new_bundled_* |
update_core() |
Adding a new default theme or plugin during a core update |
Each passes the failing file as error data, and the update screen prints it after the message: Could not copy file. /home/site/public_html/wp-content/plugins/example/includes/class-loader.php. In the unzip cases the data is the file's name inside the archive, such as example/includes/class-loader.php, with no server path in front.
So the shape of the path is a diagnosis on its own:
- A path inside the archive — extraction failed. The problem is
wp-content/upgrade/or the disk. - A full path under
plugins/,themes/or the WordPress root — extraction worked and the copy into place failed. The problem is the destination folder or that one file. - During a core update, a path relative to the WordPress root —
update_core()retries a failed copy once and reports the path without the root prefix. Same diagnosis as the line above.
It already retried with the right mode
copy_dir() does not give up on the first failure. When a copy fails, it runs chmod on the destination file with FS_CHMOD_FILE — by default your index.php mode with at least 0644 — and tries again. Only the second failure produces the message.
That rules out the most common advice. If resetting the mode to 0644 did not help, the file's mode is not the problem. What is left:
- Ownership. The file or folder belongs to a different system user than the one PHP runs as, typically after files were uploaded over FTP as one user while PHP runs as another, or after a restore run as root. Writing needs the right owner, and
chmodfrom PHP fails on a file PHP does not own. This also explains why WordPress may be asking for FTP credentials; see FS_METHOD for how it chooses the method. - Disk space or quota. See the trap below.
- A locked file. On Windows servers a file open in another process cannot be replaced. Antivirus scanning freshly extracted files does the same thing.
- An immutable or read-only file. Some hardening tools set the immutable attribute on plugin files, or mount parts of the tree read-only.
lsattron Linux shows aniflag; root has to remove it.
Check ownership and space
From a shell on the server, compare the owner of the failing file with the user PHP runs as:
ls -l wp-content/plugins/example/includes/class-loader.php
ls -ld wp-content/plugins/example wp-content/upgrade
ps -eo user,args | grep '[p]hp-fpm: pool' # worker user; the master runs as root
df -h . # free space on this filesystem
df -i . # free inodes
If the owners differ, make the WordPress tree belong to the PHP user, or to a group that user is in with group write permission. If you are on shared hosting, the host's file manager or support can reset ownership; asking them to "fix file ownership for the account" is a routine request.
The trap: a full disk does not always say so
WordPress has a disk space message: "Could not copy files. You may have run out of disk space." It appears much less often than a full disk occurs, because the free-space check in the unzip functions runs only when wp_doing_cron() is true, that is, during background automatic updates. When you click Update now on a plugin or theme on a nearly full disk, there is no pre-check; extraction simply fails partway with Could not copy file. and the name of whichever file happened to be next.
Two more ways space runs out without df -h showing it:
- Inodes. A disk can have gigabytes free and no inodes left, typically when a cache or session folder holds millions of small files.
df -ishows it. - Account quotas on shared hosting. The quota is per user, and PHP's
disk_free_space()reports the whole disk, not your share.
If the extracted file list stops in a different place on each attempt, suspect space before permissions.
Clean up and retry
- Empty
wp-content/upgrade/. WordPress clears it at the start of the next unpack anyway, but on a full disk deleting the half-extracted folders by hand frees the space now. Leaveupgrade-temp-backup/alone until you have confirmed the old plugin versions are intact. - If the site shows the maintenance message, delete
.maintenancefrom the WordPress root, as described in stuck in maintenance mode. - Fix ownership or space, then run the update again.
- If the archive itself is the problem, the message differs: see PCLZIP_ERR_BAD_FORMAT and Download failed.
Common mistakes
- Setting everything to 777. It does not fix ownership and opens the whole tree to every process on the server.
- Reading only the message and not the path, then fixing
wp-content/pluginswhen extraction intowp-content/upgradewas what failed. - Retrying again and again on a full disk. The download itself needs space too, so each attempt can fail earlier than the last.
- Copying the plugin in by hand as a different user, which works once and breaks the next update. Directory errors at the same step are covered in could not create directory.
Verify
ls -lshows the PHP user as owner ofwp-content/upgradeand of the plugin, theme or core files being updated.df -handdf -iboth show headroom.- The update completes, and Dashboard › Updates no longer lists it.
wp-content/upgrade/holds no leftover folders from the update.
Frequently asked
- Usually not. Since WordPress 6.3, plugin and theme updates move the old version to wp-content/upgrade-temp-backup first and restore it on shutdown if the update fails. Check that the plugin's folder is complete and that it is still active. If the restore also failed, WordPress shows a separate message saying it could not restore the original version.
- The singular message comes from the low-level copy and unzip functions and is followed by the path of the file that failed. The plural one appears as "Could not copy files. You may have run out of disk space.": from the unzip functions when a background update measured free space and found it short, and from a core update when the new update-core.php could not be loaded.
- No. When copying into place, WordPress already resets the failing file to the normal file mode and retries once before giving up, so a wrong mode is rarely the cause. A 777 tree makes every file writable by every process on the server and leaves ownership, the usual real cause, unchanged.