You upload a photo. WordPress thinks about it for four seconds, then returns “HTTP error.” and nothing else.

That message tells you nothing useful, and most of the others are barely better. A WordPress Media Library error is rarely one problem. It is a failure somewhere across three layers: the uploads directory, the PHP handler, and the attachment records in your database.

Guessing at fixes wastes an afternoon. Reading the actual response from async-upload.php takes ten seconds.

What this guide covers:

  • Every common error string, matched to its real cause
  • Diagnosis through debug.log, Site Health, and the Network tab
  • Fixes for blank grids, blocked file types, permissions, upload limits, and broken thumbnails

What is a WordPress Media Library Error

A WordPress Media Library error is any failure in the chain that moves a file from your computer into wp-content/uploads and then back onto the screen. Three layers break independently: the file system, the PHP handler, and the database attachment records.

Naming the layer before touching anything saves an hour of guessing.

File system: the uploads directory and its year/month subfolders have to be writable by the web server user.

PHP handler: uploadmaxfilesize, postmaxsize, and memorylimit decide whether the file survives the POST request at all.

Database: every successful upload writes one row to wpposts plus paired rows in wppostmeta, specifically wpattachedfile and wpattachmentmetadata.

Have you seen the latest WordPress statistics?

Discover the latest WordPress statistics: market share, security trends, performance data, and revenue insights that shape the web.

Check Them Out →

An upload error means the file never lands. A display error means the file sits on the server perfectly intact and the library refuses to show it, which is how images stop appearing without anyone deleting a thing.

The screen at wp-admin/upload.php renders the library. The actual file transfer runs through wp-admin/async-upload.php over Ajax, and that endpoint is where most upload failures actually surface.

Grid view fetches attachments through the WP REST API at /wp-json/wp/v2/media. List view queries the database directly with no REST call involved.

That one architectural difference explains why the same site can show a working list view and a grid that spins forever.

Front-end rendering problems sit outside this scope. A theme cropping images badly or a gallery block breaking on mobile is a template issue wearing a media costume.

Which Errors Appear Most Often in the WordPress Media Library

Seven failures cover nearly every Media Library report: HTTP error, file type not permitted, uploadmaxfilesize exceeded, missing temporary folder, unable to create directory, an endlessly loading grid, and broken thumbnails sitting over working full-size files.

Match your problem by the exact on-screen string. The wording is the diagnostic.

Error stringLayerWhat it blocks
HTTP error.PHP / image processingUpload
Sorry, this file type is not permitted for security reasons.MIME validationUpload
The uploaded file exceeds the upload_max_filesize directive in php.ini.PHP configUpload
Missing a temporary folder.Server configUpload
Unable to create directory wp-content/uploads/YYYY/MM.File permissionsUpload
Blank grid, permanent spinnerREST APIViewing only

Broken thumbnail placeholders belong in that second category. The full-size file loads fine at its direct URL while the library shows grey boxes, which means the attachment metadata is stale, not the file.

Uploads that die silently at 0% with no message at all usually got killed by a server ruleset before PHP ever saw them. Those cases sit alongside the plain inability to upload images that so many support threads open with.

One more that trips people up: an error occurred in the upload, please try again later is a Gutenberg-side message, not a core uploader string. Different message, different debugging path.

What Causes the WordPress Media Library to Break

Six root causes produce almost every listed error: directory permissions, PHP configuration ceilings, image processing library conflicts, server security rules, a blocked REST API, and database records pointing at file paths that no longer exist.

Web Almanac 2024 data puts the median WordPress mobile page at roughly 1.1 MB of image bytes, and that processing load lands on whichever image library your server runs.

Permissions and ownership: the mismatch is usually ownership, not the numeric mode. Files uploaded over FTP end up owned by your FTP user while PHP runs as www-data.

PHP ceilings: uploadmaxfilesize, postmaxsize, memorylimit, and maxexecutiontime each cut the process off at a different point. A long resize job that dies mid-run reads as a timeout rather than an upload problem.

Image processing: WordPress prefers ImageMagick and falls back to GD. When Imagick is present but misconfigured, WordPress keeps calling it and keeps failing.

modsecurity: shared hosts run rulesets that reject POST requests to async-upload.php without logging anything you can see. The upload just stops.

REST API blocked: kills the grid view specifically and leaves list view working.

Stale database paths: after a migration, wpattachedfile still points to the old directory structure or the old domain.

WordPress.org statistics for 2026 show PHP 7.4 still running on 19.288% of installs. Older PHP ships older Imagick bindings, and those bindings are behind a large share of processing failures on otherwise healthy sites. If you need the file itself, here is where php.ini lives in a WordPress install.

How Server Environment Differences Change the Error You See

Apache: reads .htaccess, so phpvalue directives work and the failure surfaces as a PHP message.

Nginx: ignores .htaccess entirely and enforces clientmaxbodysize at the server level, returning a 413 before PHP runs.

LiteSpeed: behaves like Apache for config but adds its own cache layer that can serve a stale 404 for a file that uploaded successfully thirty seconds ago.

Managed Hosts That Override Your php.ini

SiteGround presets uploadmaxfilesize at 256MB on its stack and only raises it further by request on Cloud plans. Kinsta and WP Engine apply similar server-level caps.

Editing php.ini on these platforms changes nothing. The override happens above your file.

How to Diagnose a Media Library Error Before Changing Anything

Collect evidence in four places before editing a single file: the debug log, the browser Network tab, Site Health, and the server error log. The HTTP response code from async-upload.php alone narrows the cause to one layer.

Start with debugging constants in wp-config.php:

  • define('WPDEBUG', true);
  • define('WPDEBUGLOG', true);
  • define('WPDEBUGDISPLAY', false);

Output lands in wp-content/debug.log. Keep display off on a live site unless you want your visitors reading PHP notices.

Then open DevTools, switch to the Network tab, and upload a file. Watch the request to async-upload.php.

ResponseMeaningWhere to look next
500PHP crashed mid-processdebug.log, memory_limit
403Request rejected before PHPModSecurity, security plugin
413File exceeded the server body limitNginx client_max_body_size
200 with error textWordPress rejected the fileMIME validation, permissions

Tools > Site Health > Info > Server shows the live PHP values. Read them there rather than assuming what the host set.

Test in this order: one small JPG, then a different file type, then a different browser, then incognito with extensions off. Half the “broken uploads” I have looked at were a browser extension mangling the request.

How to Fix the HTTP Error During Image Upload

The generic HTTP error message carries zero diagnostic information. It is a catch-all for a failed async-upload.php response, and five fixes resolve the overwhelming majority: switch to GD, raise memory, rename the file, limit Imagick threads, or ask the host about modsecurity.

Force the GD Library by dropping this into your theme functions file or a small plugin:

addfilter('wpimageeditors', function($e){ return ['WPImageEditorGD','WPImageEditorImagick']; });

WordPress defaults to 40M for single sites and 64M for multisite, per WP Engine documentation, which is nowhere near enough for a 12 megapixel photo. Raise it in wp-config.php with define('WPMEMORYLIMIT', '256M'); and remember the php.ini value is the real ceiling.

WPMAXMEMORYLIMIT covers admin-side processes and defaults to 256MB. If the upload dies only in the dashboard, that constant is the one to raise. A hard stop there produces a memory exhausted fatal instead of a clean message.

Filenames matter more than people expect. Apostrophes, ampersands, and accented characters break the request on plenty of stacks, so Maria's Cafe (final).jpg becomes marias-cafe-final.jpg.

For Imagick thread contention on shared hosting, add SetEnv MAGICKTHREADLIMIT 1 to .htaccess. Nginx users skip this one entirely.

When none of that moves the needle and the Network tab shows a 403, it is the host’s ruleset. Only they can lift it.

How to Fix a Blank or Endlessly Loading Media Library Grid

A grid that spins forever while files upload fine is a REST API problem, not an upload problem. Confirm it in ten seconds by loading upload.php?mode=list in the browser.

List view works and grid view does not? The REST API is being blocked. List view broken too? The problem is in the database, not the API.

Load /wp-json/wp/v2/media directly while logged in. A JSON array means the endpoint is alive. A 401, 403, or a restdisabled error names your culprit.

Security plugins are the usual suspect. Wordfence alone sits on more than 5 million active installations, and its REST hardening options plus Solid Security and the various “disable REST API” plugins all break the grid when set too aggressively.

Check the browser console next. A failed to load resource message pointing at an admin script usually means a plugin is enqueueing a broken JS file into the media modal.

After any fix, clear the object cache. Redis and Memcached will happily serve the failed REST response back to you for another hour, which is a fun way to think you fixed nothing.

Page builders complicate this. Elementor and Divi run their own media modals, so a working builder gallery with a broken core grid still points at the REST layer.

How to Fix “Sorry, This File Type Is Not Permitted for Security Reasons”

WordPress checks the file extension and the detected MIME type against wpgetmimetypes() and rejects anything where the pair does not match. Extend the whitelist through the uploadmimes filter, not by disabling validation.

Core support for image formats has moved faster than most tutorials suggest:

FormatCore supportRequirement
WebPWordPress 5.8 (2021)None
AVIFWordPress 6.5 (March 2024)PHP 8.1+ with AVIF support
SVGBlocked by defaultSanitization plugin
ICOAllowed for faviconsNone

The correct persistent method:

addfilter('uploadmimes', function($m){ $m['webp'] = 'image/webp'; return $m; });

define('ALLOWUNFILTEREDUPLOADS', true); exists and works. It also switches off MIME checking for every file type at once, so use it for a single stubborn upload and remove it the same day.

SVG stays blocked for a reason. The format is XML under the hood, so an SVG can carry a script tag that fires when an admin opens it in the media modal.

Safe SVG from 10up sanitizes on upload and restricts which roles can upload at all. It also runs files through SVGO, which handles markup cleanup and file size reduction as a side benefit.

Patchstack’s database lists six patched cross-site scripting issues in the competing SVG Support plugin, including one via SVG file upload disclosed in February 2025. Sanitization is not optional here, and neither is keeping the sanitizer updated.

False rejections happen too. PHP’s finfo extension sometimes reports a MIME type that disagrees with a perfectly valid extension, usually on files exported from older design software. Re-exporting from a current tool fixes it more often than any filter does.

How to Fix Upload Size Limits and the Missing Temporary Folder Error

Both errors come from PHP configuration rather than WordPress itself. Raise uploadmaxfilesize and postmaxsize together, keep postmaxsize larger than uploadmaxfilesize, and define WPTEMPDIR when the server has no writable temp path.

Read your current ceiling first at Media > Add New. The number under the drop zone is the live value.

Shared hosting defaults land between 2MB and 64MB, according to Bluehost documentation. A single photo off a modern phone clears 2MB without trying.

DirectiveControlsWorking value
upload_max_filesizeSingle file ceiling64M
post_max_sizeWhole POST request128M
memory_limitPHP process RAM256M
max_execution_timeScript runtime300

postmaxsize wraps the file plus form data, so setting both to 64M produces failures on files just under the limit. Give it headroom.

No php.ini access? Try .user.ini in the site root on PHP-FPM stacks, or phpvalue directives in .htaccess on Apache.

Nginx ignores both. The request entity too large response is clientmaxbodysize rejecting the upload at the server layer before PHP ever runs, and only a server config edit fixes it.

Missing a temporary folder: PHP has no writable path for uploadtmpdir. Add define('WPTEMPDIR’, ABSPATH . ‘wp-content/temp/’); to wp-config.php and create that folder.

SiteGround presets uploadmaxfilesize at 256MB across its stack and raises it further only by request on Cloud plans. Editing files on a host like that accomplishes nothing.

Honestly, if you are fighting the limit to host video files directly on WordPress, reconsider. Your uploads folder is not a CDN and your visitors will feel it.

How to Correct Uploads Folder Permissions and Ownership

Permissions control what can be done. Ownership controls who can do it. The WordPress Advanced Administration Handbook specifies 755 or 750 for directories, 644 or 640 for files, and 440 or 400 for wp-config.php.

The same documentation is blunt about the shortcut everyone reaches for: no directory should ever be 777, upload directories included.

Fix directories and files separately over SSH:

  • find /path/to/wp-content/uploads -type d -exec chmod 755 {} ;
  • find /path/to/wp-content/uploads -type f -exec chmod 644 {} ;

If the numbers already look right and uploads still fail, the problem is ownership. Run ls -la and check who owns the directory.

Files uploaded over FTP get owned by your FTP account while PHP runs as www-data, nginx, or nobody. Correct it with chown -R www-data:www-data wp-content/uploads and the write access problem disappears.

Then confirm the path itself. Settings > Media shows the upload folder, and an UPLOADS constant in wp-config.php silently overrides it.

Manual migrations and restored backups are where this breaks most often. Files land as root or as your SSH user, WordPress cannot write into the year/month folder, and the media files themselves start throwing 403 responses to visitors.

How Plugins, Themes, and Offload Services Break Media File Paths

Third-party code causes the failures that survive every server-side fix. Four categories account for almost all of them: image optimizers, offload plugins, cache layers, and page builders with their own media modals.

US WordPress sites run 21 plugins on average, per SQ Magazine’s 2025 data. That is 21 chances for something to hook into the upload pipeline.

Run the conflict test properly before blaming anything:

  • Deactivate every plugin, then test an upload
  • Switch to Twenty Twenty-Five (still the newest default theme, since WordPress 6.9 shipped without a Twenty Twenty-Six)
  • Reactivate one plugin at a time, testing after each
CategoryExampleFailure mode
OptimizersSmush, ShortPixel, EWWWDies mid-process, leaves orphaned rows
OffloadWP Offload MediaRewritten URLs break on expired credentials
Cache/CDNLiteSpeed Cache, CloudflareStale 404s on fresh uploads
BuildersElementor, DiviOwn modal fails independently

Delicious Brains documents the offload trap directly: most WP Offload Media compatibility issues appear once “remove files from server” is switched on, because gallery, slider, and optimization plugins all expect a local file.

Elementor runs on roughly 15.1 million sites and LiteSpeed Cache passed 7 million installations, so these are not edge cases. A working builder gallery next to a broken core library points straight at the media modal, not the server.

Two related failures worth separating out. A theme-level fault shows up as broken output on the front end while uploads work fine, and update failures tend to hit right after a batch update rather than randomly.

Bulk importers deserve their own mention. Media import failures during a WXR import usually mean the source URLs are unreachable, not that your library is broken.

How to Rebuild Broken Thumbnails and Repair Media Database Records

Files on the server plus no visible image in the library equals a metadata problem. Regenerate thumbnails first, then repair stale paths in wppostmeta, then import any files that exist on disk without a matching attachment row.

Thumbnails: the Regenerate Thumbnails plugin handles small libraries through the admin. WP-CLI handles everything else.

wp media regenerate --yes rebuilds every size. Add --only-missing to skip files that already have complete sets, which turns an overnight job into a coffee break.

A warning for offloaded sites: Regenerate Thumbnails only processes locally stored media. Files living on S3 have to come back down first, which is exactly why pulling media back out of the library becomes part of the repair.

Stale paths: check wpattachedfile and wpattachmentmetadata in wppostmeta. After a domain change, both still reference the old structure.

Never fix this with a raw SQL REPLACE. WordPress stores metadata as serialized PHP with byte-count prefixes, and a plain string swap corrupts every affected row while reporting success.

Use wp search-replace 'old.com' 'new.com' --all-tables --precise --dry-run first, then drop the dry run flag. Better Search Replace, maintained by WP Engine with 1+ million active installs and a 4.3 star rating, does the same job through the dashboard.

Silent serialized corruption reads exactly like a plugin conflict. Broken widgets, reverted builder layouts, missing settings, and a database-level fault that never announces itself.

Missing rows: Media Sync, used on more than 20,000 setups, scans the uploads directory and imports files that have no attachment record. Add From Server does the same but has gone years without an update.

Finish by deleting orphaned rows pointing at files you already removed. They inflate the library count and slow every query the grid makes.

How to Prevent WordPress Media Library Errors From Recurring

Prevention is mostly headroom and hygiene. Set PHP values above your working threshold rather than at it, compress images before upload, test media-touching updates on staging, and keep uploads and the database backed up as one unit.

Headroom: memorylimit at 256M, not 128M. A limit that exactly matches your heaviest job fails the first time a plugin adds one more step.

Compress first: Web Almanac 2024 data puts median WordPress mobile image delivery at 1.1 MB while Wix delivers 152 KB. Resizing a 6000px photo before it reaches the server removes the processing job that was crashing PHP.

PHP version: PHP 7.4 hit end of life in November 2022, and the WordPress core team recommends 8.1 or higher. Roughly 34.2% of sites were still on 7.4 or older in late 2025, carrying deprecated Imagick bindings with them.

Staging: test image optimizer and offload plugin updates there first. Those two categories rewrite paths, and a bad rewrite on production is a bad afternoon.

WordPress 7.0 landed on May 20, 2026, following 6.9 in December 2025. Major releases touch media handling often enough that a staging pass costs less than the alternative, and it also catches the kind of upgrade failure that only appears with your specific plugin stack.

Back up wp-content/uploads and the database together. Restoring files without their attachment records rebuilds the exact broken state you were trying to escape.

Melapress found in its 2025 survey that the 73% of professionals without a recovery plan take three to four times longer to recover. Knowing where your backups live beats improvising at 11pm.

Last piece: keep an eye on debug.log size and rotate it. Leaving PHP error output switched on for months produces a multi-gigabyte file that fills the disk, and a full disk breaks uploads all over again.

FAQ on WordPress Media Library Error

Why does WordPress say “HTTP error” when I upload an image?

The string is a catch-all for a failed async-upload.php response. Switch the image editor from Imagick to GD, raise memorylimit to 256M, and rename files containing apostrophes or accented characters.

A 403 in DevTools means modsecurity.

How do I fix a Media Library that shows a blank grid?

Load upload.php?mode=list. If list view works, the REST API is blocked, usually by a security plugin.

Test /wp-json/wp/v2/media directly, loosen the REST hardening, then clear the object cache before retesting.

Why can I upload images but not see them in the Media Library?

The files exist and the attachment metadata does not match them. Check wpattachedfile in wppostmeta for stale paths, then run thumbnail regeneration.

Broken thumbnails over working full-size images point to metadata, never permissions.

How do I increase the maximum upload file size in WordPress?

Edit uploadmaxfilesize and postmaxsize in php.ini, keeping postmaxsize larger. Use .user.ini or .htaccess when php.ini is off limits.

Nginx needs clientmaxbodysize. Managed hosts cap this at the server level regardless of what you edit.

Can I upload SVG files to WordPress?

Not by default. SVG is XML and can carry executable scripts, so core blocks the format.

Install Safe SVG from 10up, which sanitizes files on upload and restricts which user roles can upload them at all.

What permissions should the wp-content/uploads folder have?

Directories 755, files 644, per the WordPress Advanced Administration Handbook. Never 777, upload directories included.

If those values are already correct and writes still fail, the real problem is ownership, not the numeric mode.

Why are my thumbnails broken after a site migration?

Serialized metadata still points at the old domain or directory structure. Run wp search-replace with the precise flag, or use Better Search Replace.

A raw SQL replace corrupts serialized rows silently and reads exactly like a plugin conflict.

Does deactivating plugins delete my media files?

No. Deactivation never touches wp-content/uploads.

Optimization plugins can leave orphaned attachment rows behind, and offload plugins stop rewriting URLs when disabled, but the original files stay on the server or in the bucket.

Why does the same image upload fine on one site and fail on another?

Server environment. Apache reads .htaccess, Nginx enforces clientmaxbodysize, and different PHP versions ship different Imagick bindings.

Compare Tools > Site Health > Info > Server on both installs and read the actual values.

How do I find out what is actually causing the error?

Enable WPDEBUG and WPDEBUGLOG in wp-config.php, then read wp-content/debug.log.

Open DevTools and watch the async-upload.php request: 500 means PHP crashed, 403 means the request was rejected, 413 means the file exceeded the server limit.

Conclusion

Almost every WordPress Media Library error resolves once you stop treating it as one bug. Identify the layer first: file ownership, MIME validation, the REST endpoint, or serialized metadata in wp_postmeta.

Then change one thing at a time and test.

Keep a note of every edit you make. Six months from now, that Imagick to GD switch sitting in your functions file will make no sense without one.

Two habits prevent most repeat visits:

  • Resize images before they ever reach the server
  • Push plugin and PHP version changes through staging first

Media failures rarely appear out of nowhere. Something changed: a plugin update, a host migration, a PHP bump.

Find that change and you have usually found the fix.