WordPress "HTTP Error" When Uploading Images — 7 Real Causes and the Fix for Each
Retry once. If it fails again, upload a 200 KB test image — if that one works, your server ran out of memory resizing the big file, and define('WP_MEMORY_LIMIT', '512M'); in wp-config.php fixes it.
Despite the name, this has almost nothing to do with HTTP. The uploader posted your file, waited for a JSON reply, and got back something else — a PHP crash, a timeout, a security module's block page. It has no idea which, so it prints the only thing it knows.
You drag a hero image into the Media Library, the progress bar crawls to the end, and the thumbnail turns red: HTTP error. Two words, a full stop, no detail. Upload the same file again and it sometimes works. Upload a screenshot and it always works. That inconsistency is the most useful clue you have, and it points somewhere specific.
Why the message tells you nothing
The media uploader is JavaScript. It sends your file to async-upload.php and expects a small blob of JSON describing the new attachment. Anything that isn't that JSON — a PHP fatal error, an empty response after a timeout, an HTML error page from a firewall — fails to parse, and the uploader falls back to a generic label.
So "HTTP error" is not a diagnosis. It's the absence of one. The real failure happened server-side and was never written to your screen. The good news: there are only a handful of things that produce it, and you can separate them without reading a single log file.
The 30-second triage
Three uploads tell you which family of cause you're in. Do them in order and stop at the first one that changes the outcome.
- Upload the same file again. Genuinely transient timeouts exist, particularly on shared hosting at busy times. If the retry succeeds, you're done — nothing is broken.
- Upload a small JPEG, under 200 KB. If the small one lands and the large one doesn't, the problem is a resource limit: memory, execution time, or an image library ceiling. Skip to causes 1–3.
- Rename the file to
test.jpg— no spaces, no accents, no&, no emoji — and upload it. If the rename fixes it, the problem is the filename or a security filter. Skip to causes 4–5.
If every image fails, including a 20 KB one with a plain name, you're not looking at a limit at all. Go straight to cause 6 and check whether the uploads folder is writable — that failure mode usually announces itself with "Unable to create directory" instead, but a fatal error at the wrong moment can surface as an HTTP error.
The seven causes, in order of likelihood
1. PHP runs out of memory generating thumbnails
This is the answer most of the time. When an image arrives, WordPress doesn't just store it — it decodes it into raw pixels and renders every registered size: thumbnail, medium, large, plus whatever your theme and plugins added. A 4000 × 3000 photo is 12 million pixels, and holding that uncompressed while writing six copies of it can want more memory than the process is allowed.
Add this to wp-config.php, above the line that says to stop editing:
define('WP_MEMORY_LIMIT', '512M');
Note the ceiling: this constant can only raise WordPress's request to PHP, never past what the host actually permits. If memory_limit is capped at 256M in the server config, the constant is quietly ignored and you need the host to change it. Tools → Site Health → Info → Server shows the real value you're working with.
2. The request times out mid-resize
Same root cause, different limit. Resizing a large image can run for tens of seconds, and if max_execution_time is 30 the process is killed before it can reply. The signature is distinctive: the progress bar reaches 100%, sits there for a while, then fails. A short pause followed by an instant failure is memory; a long wait followed by failure is time.
Hosts vary on whether you can raise this yourself. Many panels expose it as "Max execution time" under PHP settings; on managed WordPress hosting it's usually fixed and you fix the image instead.
3. ImageMagick is installed but restricted
WordPress prefers ImageMagick over GD when both exist. ImageMagick has its own resource policy — often in /etc/ImageMagick-6/policy.xml — and hosts sometimes set memory or area limits far below what a large photograph needs. The result is an image library that refuses the job while PHP still has memory to spare, which makes the "raise the memory limit" advice look wrong.
You can force WordPress back to GD by dropping this in a small plugin or your theme's functions.php:
add_filter('wp_image_editors', fn() => ['WP_Image_Editor_GD']);
Treat it as a diagnostic first. If GD succeeds where ImageMagick failed, you've found your cause, and the durable fix is a policy change from the host rather than permanently downgrading your image quality path.
4. A security module blocks the request
ModSecurity, a WAF rule, or a firewall plugin can decide an upload looks suspicious and return an HTML block page. The uploader can't parse it, so: HTTP error. Two tells — it fails instantly regardless of file size, and it often triggers on particular filenames or file types rather than all of them.
Ask the host to check the ModSecurity log for your IP at the moment of the upload. It's usually one over-eager rule, and hosts disable it per-site routinely.
5. The filename itself
Spaces are fine. Accents, #, &, %, emoji, and names exported straight out of a design tool as Frame 12 — Copy@2x.png are not always fine, depending on the filesystem and the rewrite rules in front of it. This is the cheapest cause to eliminate, which is why it's in the triage: rename to test.jpg and retry.
It's also the cause most worth preventing rather than fixing, since it recurs with every batch of exports.
6. A plugin fatals during the upload
Image optimisers, watermark plugins, CDN offloaders and media library organisers all hook into the upload and run their own code before WordPress replies. A fatal in any of them produces exactly the same generic message.
The fast test is unglamorous: deactivate image-related plugins, upload, and reactivate one at a time. Do it on staging if the site is live. If the very first upload after deactivating everything succeeds, you've saved yourself an afternoon in the server config.
7. A proxy or CDN cuts the connection
If the site sits behind Cloudflare or a similar layer, that layer has its own body-size and timeout limits, independent of PHP. A slow upload can hit a gateway timeout well before the origin gives up. The tell is that failures correlate with your connection speed rather than with the file — the same image that fails from a café uploads fine from the office.
Getting the real error out of the server
If the triage didn't land, stop guessing and read the actual failure. Add this to wp-config.php:
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
Retry the upload, then open wp-content/debug.log. The last entry will name the file and function that died — usually something in class-wp-image-editor-imagick.php for the resource cases, or your optimisation plugin for the fatal ones. Turn all three off again when you're finished. A world-readable debug log on a production site is its own problem.
The fix that outlasts the config edit
Every cause above except the firewall shares a trigger: the image was bigger than it needed to be. WordPress scales anything wider than 2560 pixels on upload, and that scaling pass is precisely where memory, execution time and ImageMagick limits are reached.
A hero image renders at perhaps 1600 pixels wide. A content image renders at 800. Exporting at 4x from a design file and letting the server sort it out means paying for a resize on every upload, forever, on a machine you don't control. Our WordPress image size guide has the widths worth exporting at, and the export settings guide covers where the oversized defaults come from in the first place.
Raising the memory limit is still worth doing. It just stops being the thing standing between you and a published page.
Other upload messages, decoded
| What WordPress says | What it actually means |
|---|---|
| HTTP error. | The server replied with something that wasn't JSON. Usually memory or time exhausted during resizing. |
| Post-processing of the image failed | Same family, caught one step later — the upload landed but the resize didn't finish. |
| Exceeds the maximum upload size for this site | Rejected before transfer, on upload_max_filesize. A cleaner failure than this one. |
| Sorry, this file type is not permitted for security reasons | The file arrived and WordPress declined the format, not the size. |
| Missing a temporary folder | PHP has nowhere to stage the upload. A configuration fault, not a limit. |
| Unable to create directory wp-content/uploads/… | Permissions or a full disk. Nothing to do with the image. |
FAQ
What does "HTTP error" mean when uploading to WordPress?
It means the uploader received a response it couldn't read — a PHP fatal, a timeout, or a firewall page — instead of the JSON it expected. The underlying cause is most often PHP running out of memory while generating thumbnail sizes for a large image.
Why do small images upload but large ones fail?
Because the failure happens during processing, not transfer. WordPress makes several resized copies of every image after it arrives, and that work is what exhausts memory or execution time. Small files finish before either limit is reached.
Does increasing the memory limit fix it?
It fixes the most common cause. Add define('WP_MEMORY_LIMIT', '512M'); to wp-config.php. If your host caps PHP memory lower, the constant is ignored and the host has to raise it.
Can a plugin cause the HTTP error?
Yes — image optimisers, watermarkers and CDN offloaders all run during the upload. Deactivate them one at a time and retry the same file to identify which.
Is it my internet connection?
Usually not. The file normally reaches the server intact and fails afterwards. A genuinely dropped connection is worth ruling out by uploading a small image first.
How big should images be before I upload them?
Under 2560 pixels wide, ideally a few hundred kilobytes. WordPress scales anything wider on upload, and that scaling step is where this error lives.
Send images that never need resizing
Fig2WP uploads straight from your Figma selection into the Media Library. Pro adds a max-width cap and a quality slider applied before the file leaves Figma — so what reaches WordPress is already the size the page renders, and there's no oversized original for the server to choke on.