HTTP-fout bij het uploaden van media in WordPress

WordPress toont een kale "HTTP error" in de mediabibliotheek zodra de server een upload halverwege afkeurt. De echte oorzaak is bijna altijd een groottelimiet, een geheugenprobleem van Imagick, een timeout, of een WAF-regel. Lees de serverlog en fix het juiste plafond.

Je kiest een JPEG in de WordPress-mediabibliotheek, het voortgangsbalkje komt een stukje op gang, en dan klapt de thumbnail om naar een rood blokje met HTTP error. Geen bestandspad, geen statuscode, geen hint over wat er stuk ging. Alleen die twee woorden.

De melding is met opzet vaag. WordPress toont hem zodra de JavaScript-uploader in wp-admin een reactie krijgt die geen 200 is (of een lege body), ongeacht of de fout in PHP, de webserver of een proxy ervoor zit. De echte oorzaak staat altijd ergens in een log. Dit artikel loopt de vijf dingen langs die de fout in de praktijk veroorzaken, hoe je er binnen tien minuten achter komt welke het is, en hoe je elke oorzaak fixt met een verificatie die je zelf kunt doen voordat je 'm afschrijft.

Wat de fout eigenlijk betekent

De media-uploader van WordPress is een browser-script dat elk bestand als multipart-request POST naar /wp-admin/async-upload.php. Gaat dat goed? Dan krijgt de browser JSON terug met een attachment-ID en een thumbnail-URL. Bij elke andere reactie geeft de uploader op en toont HTTP error in de bibliotheek. Meer context geeft de melding nooit.

De echte statuscode vind je in het netwerktabblad van je browser. Open je developer tools (F12 in Chrome of Firefox), ga naar Network, probeer de upload opnieuw en klik op de regel async-upload.php. De statuscode op die regel is de code die je nodig hebt:

  • 413 Payload Too Large wijst naar een groottelimiet in Apache, nginx of een proxy zoals Cloudflare.
  • 500 Internal Server Error wijst naar PHP zelf, bijna altijd geheugen of een timeout halverwege de upload.
  • 502 Bad Gateway of 504 Gateway Timeout wijst naar PHP-FPM die crasht of over zijn eigen request-timeout heen loopt.
  • 403 Forbidden wijst naar een WAF-regel (mod_security, Wordfence, Sucuri, een Cloudflare Firewall-regel).
  • Een request die compleet is maar een lege of niet-JSON body teruggeeft wijst naar een PHP fatal die de worker kilde nadat de response al was begonnen.

Dat ene getal schroeft de diagnose terug van "vijf mogelijke oorzaken" naar "één of twee". Ga dus niet eerst knoppen draaien. Haal eerst die statuscode op.

Oorzaken op volgorde van waarschijnlijkheid

  1. Het bestand is groter dan upload_max_filesize of post_max_size. De PHP-defaults zijn upload_max_filesize = 2M en post_max_size = 8M, en goedkope hosts laten die vaak op 8 of 16 MB staan. Een moderne telefoonfoto van 12 MP weegt al snel 4 tot 6 MB, en een rauwe JPEG direct uit een camera kan zo 20 MB zijn. Zodra het bestand één van de twee limieten overschrijdt weigert PHP de upload (zie maximale uploadgrootte verhogen in WordPress voor de fix), en je ziet een 413 of een lege response.
  2. Imagick loopt leeg op een grote afbeelding. Dit is de op één na meest voorkomende oorzaak, en tegelijk de lastigste om zelf aan te wijzen. Het bestand past wel binnen de uploadlimiet, maar zodra WordPress Imagick vraagt om thumbnails te genereren, laadt Imagick de hele foto ongecomprimeerd in het geheugen. Een JPEG van 6000x4000 die op schijf 4 MB is kan makkelijk rond de 200 MB werkgeheugen nodig hebben om te decoderen. Staat de PHP memory_limit lager? Dan crasht de upload als 500 met Allowed memory size exhausted in de log.
  3. De upload loopt over max_execution_time, max_input_time of de PHP-FPM request-timeout heen. Een trage verbinding die een bestand van 30 MB uploadt knalt makkelijk door de default max_input_time van 60 seconden heen. Dat is de timer specifiek voor het ontvangen van POST-data, en die wordt standaard vergeten. Op PHP-FPM kilt request_terminate_timeout in de pool-config bovendien workers die langer draaien dan die waarde, meestal 30 of 60 seconden. Beide geven een 500 of 504 en een lege response.
  4. Apache LimitRequestBody of een WAF-regel blokkeert het verzoek voordat PHP het ziet. De LimitRequestBody-directive van Apache zet een plafond op de grootte van het HTTP-request body, op webserverniveau, nog voor PHP in beeld komt. Sommige Red Hat-achtige hosts leveren hem met een default van 512 KB. Security-regels in mod_security, Wordfence, Sucuri of een Cloudflare WAF kunnen ook uploads tegenhouden die een patroon matchen (een bestandsnaam met <script>, een MIME-type dat als risicovol is geflagd, een ongewoon grote multipart-body). Je ziet dit dan terug als 403, 413 of een request die PHP nooit bereikt.
  5. Laatste redmiddel: een rare bestandsnaam of bestandstype. Dit is de folklore-fix uit 2014 en is in 2026 zelden nog de echte oorzaak. WordPress strijkt de meeste probleemtekens uit bestandsnamen weg via sanitize_file_name() voordat ze op schijf landen, dus apostrofs, spaties en accenten breken bijna nooit iets. Als je oorzaken 1 tot en met 4 echt hebt uitgesloten en een rename is het enige dat één specifiek bestand fixt, dan zit er vrijwel altijd een WAF-regel achter die op de originele bestandsnaam matcht, en is het een workaround voor oorzaak 4.

Achterhaal welke oorzaak het is

Voordat je aan plafonds gaat draaien: zoek eerst uit welk plafond je echt raakt. Anders verhoog je iets wat het probleem niet was en verstop je de echte oorzaak.

Check 1: lees de statuscode in het netwerktabblad van je browser. Dit is veruit de meest informatieve stap en tegelijk de stap die in bijna elk walkthrough wordt overgeslagen. Open devtools, upload opnieuw, en lees de status op de regel async-upload.php. Leg 'm naast de lijst hierboven. Je weet dat je de juiste regel te pakken hebt als de statuscode een 413, 500, 502, 504 of 403 is met een timestamp die aansluit op de mislukte upload.

Check 2: lees de server error log. Open je hostingpaneel en zoek "Error Logs" op (cPanel, Plesk, DirectAdmin en de meeste managed hosts bieden dit aan). De regel met dezelfde timestamp vertelt je precies welke oorzaak het is. Heb je SSH-toegang? Dan staat de log op /var/log/apache2/error.log (Apache) of /var/log/nginx/error.log (nginx). Je wilt iets zien als:

PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted
(tried to allocate 8192 bytes) in /.../wp-admin/includes/image.php on line 412
PHP Warning:  POST Content-Length of 25165824 bytes exceeds
the limit of 8388608 bytes
client intended to send too large body: 25165824 bytes
ModSecurity: Access denied with code 403

Elke regel wijst naar een andere oorzaak uit het lijstje. Je weet dat je de goede regel te pakken hebt als de timestamp klopt en de tekst een concrete limiet of regel noemt.

Check 3: lees je huidige PHP-limieten uit. Zet een kort diagnosebestandje in de root van je WordPress-installatie dat de vijf waarden dumpt die uploads beïnvloeden:

<?php
// upload-check.php, na gebruik weer verwijderen
echo 'upload_max_filesize: ' . ini_get('upload_max_filesize') . PHP_EOL;
echo 'post_max_size:       ' . ini_get('post_max_size')       . PHP_EOL;
echo 'memory_limit:        ' . ini_get('memory_limit')        . PHP_EOL;
echo 'max_execution_time:  ' . ini_get('max_execution_time')  . PHP_EOL;
echo 'max_input_time:      ' . ini_get('max_input_time')      . PHP_EOL;

Open https://jouwsite.nl/upload-check.php en lees de waarden. Verwachte output op een gezonde WordPress-host: upload_max_filesize: 64M, post_max_size: 64M, memory_limit: 256M, max_execution_time: 120, max_input_time: 120. Staat een van die waarden tegen de PHP-defaults aan (2M, 8M, 128M, 30, 60)? Dan heb je waarschijnlijk de boosdoener. Gooi het bestandje weg zodra je de waarden hebt gelezen.

Fix 1: verhoog upload_max_filesize en post_max_size

Dit is de fix voor oorzaak 1 (413-responses, "POST Content-Length ... exceeds the limit", bestanden boven de 8 MB die afketsen op de default). De twee waarden horen bij elkaar, en post_max_size moet altijd minstens zo hoog zijn als upload_max_filesize, anders breekt het juist de andere kant op.

  1. Log in op je hostingpaneel en open MultiPHP INI Editor (cPanel), PHP Settings (Plesk), PHP Selector (DirectAdmin) of PHP Configuration (hPanel).
  2. Selecteer het domein waar de uploads falen.
  3. Zet upload_max_filesize op 64M en post_max_size op 64M. Ga niet gelijk naar 512M. Een redelijk plafond vangt echt stukke uploads nog wel af en houdt het request begrensd.
  4. Sla op. De meeste panelen passen de wijziging toe op het volgende request, zonder restart.

Biedt je host die knoppen niet? Zet ze dan in een .user.ini in de root van je WordPress-install (dezelfde map als wp-config.php):

upload_max_filesize = 64M
post_max_size = 64M

PHP-FPM leest .user.ini-bestanden standaard elke 300 seconden opnieuw in, dus wacht even vijf minuten voordat je test.

Verifieer: laad het diagnosebestandje uit Check 3 opnieuw. Je weet dat de waarden zijn doorgekomen als beide nu op 64M staan. Probeer daarna de upload opnieuw. Je weet dat de fix houdt als het bestand in de mediabibliotheek belandt en de JSON-response op de regel async-upload.php een 200 is met een attachment-ID erin.

Fix 2: verhoog memory_limit voor beeldverwerking

Dit is de fix voor oorzaak 2, waarin het bestand wel past maar de thumbnail-generatie het geheugen opeet. De regel in je error log leest dan Allowed memory size ... exhausted en wijst naar een bestand in wp-admin/includes/image.php of wp-includes/class-wp-image-editor-imagick.php.

De PHP memory_limit verhogen is de standaardfix, en de volledige procedure staat in het aparte artikel over Allowed memory size exhausted. Voor het upload-geval specifiek: zet memory_limit op 256M in je hostingpaneel, of voeg memory_limit = 256M toe aan je .user.ini.

Helpt 256 MB niet en zit je op shared hosting waar Imagick de standaard editor is? Dan kun je WordPress dwingen om GD te gebruiken. GD is minder veelzijdig maar trekt duidelijk minder werkgeheugen. Het juiste patroon, geverifieerd tegen de documentatie van de wp_image_editors-filter, is een korte mu-plugin op wp-content/mu-plugins/prefer-gd.php:

<?php
// GD boven Imagick verkiezen voor thumbnail-generatie.
add_filter( 'wp_image_editors', function( $editors ) {
    return array( 'WP_Image_Editor_GD', 'WP_Image_Editor_Imagick' );
} );

De filter krijgt een array met editor-classes in prioriteitsvolgorde. Door WP_Image_Editor_GD als eerste terug te geven probeert WordPress eerst GD, en pas als fallback Imagick. Door het snippet in mu-plugins te zetten kan een thema-update het niet per ongeluk overschrijven.

Verifieer: probeer de upload opnieuw. Je weet dat de fix houdt als het bestand in de bibliotheek belandt en de error log geen nieuwe Allowed memory size-regels meer toont voor afbeeldingen. Met Query Monitor kun je desgewenst bevestigen welke editor het verzoek heeft afgehandeld.

Fix 3: verhoog execution en input timeouts

Dit is de fix voor oorzaak 3, waarin een grote upload over de klok heen loopt. Het symptoom is een 500 of 504 op de regel async-upload.php, en een error log-regel met Maximum execution time of POST Content-Length, of helemaal geen PHP-error omdat PHP-FPM de worker eerder had gekild.

Verhoog max_execution_time én max_input_time in je hostingpaneel of in .user.ini:

max_execution_time = 300
max_input_time = 300

Die tweede is degene die het vaakst wordt vergeten. max_input_time is de timer voor het ontvangen van POST-data, los van de wall clock van het script zelf, en staat standaard op 60 seconden. De volledige procedure voor PHP-executiontimeouts staat in het artikel over Maximum execution time exceeded.

Op PHP-FPM zit er nog een laag bovenop: request_terminate_timeout in de pool-config (meestal /etc/php/8.3/fpm/pool.d/www.conf). Dat is een harde kill boven PHP's eigen timers, en op managed hosting kan alleen de host daar iets aan veranderen.

Verifieer: laad het diagnosebestandje opnieuw. Je weet dat de PHP-kant is doorgekomen als max_execution_time en max_input_time allebei op 300 staan. Probeer de upload opnieuw. Je weet dat de fix houdt als een groot bestand dat eerder na 30 of 60 seconden crashte nu netjes doorkomt en async-upload.php een 200 geeft in het netwerktabblad.

Fix 4: check Apache LimitRequestBody en WAF-regels

Dit is de fix voor oorzaak 4, waarin de webserver of een WAF het request afkeurt voordat PHP überhaupt draait. De tell is dat je PHP-limieten ruim staan, de PHP error log stil is, maar de upload toch 413 of 403 teruggeeft zonder bijbehorende PHP-regel.

Bij Apache check je LimitRequestBody in de virtual host-config of in .htaccess. De directive staat standaard op 0 (geen limiet), maar sommige hosts overschrijven dat. Op cPanel-hosts met EasyApache staat de waarde in de Apache-configuratie-editor. Zet hem op minstens 67108864 (64 MB), zodat hij even hoog staat als je post_max_size:

LimitRequestBody 67108864

Bij nginx is het equivalent client_max_body_size in het server- of location-blok, meestal in /etc/nginx/nginx.conf of een site-specifiek bestand. Zet 'm op 64m:

client_max_body_size 64m;

Geen van beide is doorgaans aanpasbaar op shared hosting. Geeft het hostingpaneel geen knop? Open dan een supportticket met de exacte regel uit je error log.

Voor WAF-regels is de diagnose gericht uitschakelen. Gebruikt de site Wordfence? Zet de firewall dan tijdelijk in "Learning Mode" en probeer opnieuw. Bij Cloudflare check je het Security Events-log op een block voor de upload-URL. Zie je ModSecurity: Access denied op een host met mod_security? Dan moet de host de specifieke regel voor /wp-admin/async-upload.php whitelisten. Dat kun je niet zelf.

Verifieer: probeer de upload opnieuw. Je weet dat de fix houdt als de regel async-upload.php een 200 geeft, de server error log geen nieuwe 413- of mod_security-regels meer heeft, en een volgende grote upload ook probleemloos doorkomt.

Fix 5 (laatste redmiddel): hernoem het bestand

Het hernoemen van het bestand is de folklore-fix die je nog vaak tegenkomt in oude forum-threads. In 2026 is dit bijna nooit de echte oorzaak, omdat sanitize_file_name() de meeste rare tekens al weghaalt voordat het bestand op schijf belandt. Het enige scenario waarin een rename écht helpt, is wanneer een WAF-regel op de originele bestandsnaam matcht, en dan is oorzaak 4 het échte probleem en is de rename alleen een workaround.

Heb je oorzaken 1 tot en met 4 doorlopen en valt één specifiek bestand telkens onderuit terwijl andere wel werken? Hernoem 'm dan tijdelijk naar iets simpels als test-image.jpg en probeer opnieuw. Je weet dat de rename een workaround voor een WAF was als de nieuwe naam wel werkt terwijl de oude bestandsnaam structureel faalt, ook al zijn je PHP- en webserverlimieten ruim. De correcte fix is dan alsnog fix 4 (regel of bestand whitelisten), niet een permanent rename-beleid.

Wanneer je moet escaleren

Heb je fixes 1 tot en met 4 doorlopen en ketst de upload nog steeds af? Verzamel dan onderstaande voor je een ticket opent of een developer inschakelt. Het is precies het lijstje dat iemand met ervaring als eerste gaat vragen:

  • Het exacte bestand dat faalt, inclusief grootte in MB en afmetingen in pixels.
  • De statuscode uit het netwerktabblad op de regel async-upload.php (413, 500, 502, 503, 504, 403, of 200 met een lege body).
  • De bijbehorende regel uit de server error log (check "Error Logs" in je hostingpaneel, of /var/log/apache2/error.log / /var/log/nginx/error.log als je SSH-toegang hebt), mét timestamp.
  • De vijf waarden uit het diagnosebestandje in Check 3: upload_max_filesize, post_max_size, memory_limit, max_execution_time, max_input_time.
  • Je WordPress-versie, PHP-versie en SAPI (te vinden onder Hulpmiddelen: Sitediagnose: Info: Server).
  • Je hostingpakketnaam en of je zelf bij .user.ini, .htaccess of de PHP-FPM pool-config kunt.
  • Of de site achter Cloudflare of een andere proxy hangt, en of de fout ook optreedt als je die even omzeilt.
  • De lijst met actieve security plugins (Wordfence, Sucuri, iThemes Security, All-In-One Security).

Zet dat allemaal in je eerste bericht. Dan gaat je ticket direct naar de juiste engineer, zonder heen-en-weer, en hoef je niet twee keer uit te leggen wat je al geprobeerd hebt.

Zie je tegelijk een kale 500 Internal Server Error op de front-end terwijl ook de admin-upload struikelt? Dan zijn die twee vrijwel zeker hetzelfde incident: een PHP fatal tijdens beeldverwerking kan elk verzoek neerhalen waarin de code wordt aangeroepen, niet alleen in de mediabibliotheek. Behandel het dan als één probleem en volg voor de diagnose het 500-artikel.

Hoe je 'm voorkomt

Een site die hier herhaaldelijk tegenaan loopt vertelt je dat zijn hostingplafond te dicht tegen de dagelijkse workload aan zit. Drie gewoontes duwen die marge terug:

  • Verklein afbeeldingen voor je ze upload. Een hero-image hoeft geen 20 MP-raw te zijn. Schaal telefoonfoto's terug naar 2000 pixels aan de lange kant en comprimeer JPEG's met een tool als Squoosh. Dat verlaagt zowel de uploadgrootte als het werkgeheugen dat Imagick nodig heeft.
  • Zet PHP-limieten één keer goed, niet telkens in paniek. Stel upload_max_filesize, post_max_size, memory_limit en max_input_time in op waarden die je echte uploads met marge dekken, en laat ze staan. Plafonds aanpassen tijdens een incident is hoe foutjes erin sluipen.
  • Pas het hostingpakket aan op de media-volumes. Upload je regelmatig grote afbeeldingen en loopt je goedkope host telkens tegen limieten aan? Dan is upgraden goedkoper dan een zaterdagavond debuggen. Moderne WordPress-hosting levert standaard nette defaults, en voorkomt deze fout eigenlijk gewoon bij voorbaat.

Wil je dat dit niet steeds jouw probleem is?

Als storingen blijven terugkomen, is de 'fix' vaak consistent beheer: updates, backups en monitoring die niet versloffen.

Bekijk WordPress onderhoud

Doorzoek deze site

Begin met typen om te zoeken, of blader door de kennisbank en blog.