Salah satu kasus yang sering membingungkan saat membangun fitur upload gambar di Laravel adalah file gagal terkirim dengan pesan 413 Request Entity Too Large. Di sisi pengguna, gejalanya biasanya sederhana: tombol upload ditekan, lalu request gagal, halaman error muncul, atau frontend hanya menampilkan respons gagal tanpa pesan yang jelas. Di sisi developer, masalah ini sering disangka berasal dari Laravel, padahal akar masalahnya bisa berada di beberapa lapisan sekaligus: Nginx, Apache, PHP-FPM/PHP, dan rule validasi Laravel.

Artikel ini fokus pada studi kasus praktis: upload file gambar di Laravel gagal dengan error 413. Tujuannya bukan hanya memberi daftar setting, tetapi membantu Anda menemukan titik kegagalan secara sistematis. Jika dilakukan berurutan, Anda bisa cepat tahu apakah request ditolak sebelum masuk Laravel, dipotong oleh PHP, atau justru lolos ke aplikasi tetapi gagal di validasi.

Memahami Gejala 413 pada Upload Gambar

Status 413 Request Entity Too Large berarti ukuran request melebihi batas yang diizinkan oleh server. Pada konteks upload gambar, request body berisi file multipart/form-data. Jika batas ukuran terlalu kecil, server bisa menolak request sebelum kode controller Laravel dijalankan.

Gejala umum yang sering muncul:

  • Browser menampilkan halaman error 413 dari Nginx atau Apache.
  • Frontend SPA mengembalikan HTTP 413 saat mengirim FormData.
  • Controller Laravel tidak pernah terpanggil.
  • Tidak ada log validasi Laravel karena request sudah berhenti di web server.
  • Upload file kecil berhasil, tetapi file sedikit lebih besar langsung gagal.

Ini penting: jika error yang muncul benar-benar 413, sering kali Laravel belum menerima request-nya. Artinya, memeriksa rule max di validasi saja tidak cukup. Anda perlu mengecek batas di lapisan bawah lebih dulu.

Urutan Cek yang Benar: Mulai dari Web Server, Lalu PHP, Baru Laravel

Untuk mempercepat debugging, gunakan urutan berikut:

  1. Cek Nginx: client_max_body_size
  2. Cek Apache: LimitRequestBody bila digunakan
  3. Cek PHP: upload_max_filesize dan post_max_size
  4. Cek Laravel validation: rule seperti image, mimes, max, atau dimensions
  5. Verifikasi ulang lewat log, endpoint debug, dan pengujian upload nyata

Kenapa urutannya demikian? Karena request upload harus lolos dari lapisan paling luar dulu. Kalau Nginx sudah menolak request 10 MB, maka menaikkan validasi Laravel ke 20 MB tidak akan mengubah apa-apa.

Penyebab Umum di Nginx: client_max_body_size

Pada deployment Laravel dengan Nginx, penyebab paling umum error 413 adalah nilai client_max_body_size terlalu kecil. Secara default, beberapa konfigurasi Nginx menetapkan batas yang tidak cocok untuk upload gambar dari kamera ponsel modern, yang ukurannya bisa beberapa megabyte per file.

Cara cek konfigurasi Nginx

Periksa file konfigurasi utama atau virtual host, misalnya:

/etc/nginx/nginx.conf
/etc/nginx/conf.d/default.conf
/etc/nginx/sites-available/app.conf

Cari apakah ada directive berikut:

client_max_body_size 2M;

Jika upload gambar Anda bisa mencapai 5 MB atau 10 MB, nilai ini harus disesuaikan. Contoh:

server {
    listen 80;
    server_name example.com;
    root /var/www/app/public;

    client_max_body_size 10M;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

Setelah mengubah konfigurasi:

sudo nginx -t
sudo systemctl reload nginx

Kenapa ini bekerja? Karena Nginx memeriksa ukuran request body sebelum meneruskannya ke PHP-FPM. Jika ukuran melebihi client_max_body_size, Nginx akan langsung mengembalikan 413.

Perhatikan bahwa client_max_body_size bisa didefinisikan di level http, server, atau location. Nilai yang lebih spesifik bisa menimpa nilai global.

Kesalahan umum di Nginx

  • Mengubah file konfigurasi yang salah, lalu me-reload Nginx tanpa efek.
  • Menambah setting di satu vhost, padahal request masuk ke vhost lain.
  • Lupa reload service setelah perubahan.
  • Berjalan di container, tetapi konfigurasi diubah di host yang tidak dipakai container.

Penyebab Umum di Apache: LimitRequestBody

Jika aplikasi Laravel berjalan di Apache, error serupa dapat dipicu oleh LimitRequestBody. Directive ini membatasi ukuran request body yang diterima.

Contoh konfigurasi Apache:

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/app/public

    LimitRequestBody 10485760

    <Directory /var/www/app/public>
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

Nilai di atas adalah 10 MB dalam byte. Setelah perubahan, reload Apache:

sudo apachectl configtest
sudo systemctl reload apache2

Tidak semua instalasi Apache secara eksplisit memakai LimitRequestBody, tetapi jika directive ini ada dan terlalu kecil, upload akan gagal sebelum mencapai Laravel.

Kapan Apache menjadi tersangka utama?

  • Server Anda memang memakai Apache, bukan Nginx.
  • Error page yang muncul jelas berasal dari Apache.
  • Laravel log kosong, tetapi request upload ditolak di level server.

Penyebab Umum di PHP-FPM/PHP: upload_max_filesize dan post_max_size

Setelah web server, lapisan berikutnya adalah PHP. Dua parameter terpenting untuk upload adalah:

  • upload_max_filesize: ukuran maksimum satu file upload
  • post_max_size: ukuran maksimum seluruh body POST

Untuk upload gambar, post_max_size harus lebih besar atau minimal sama dengan upload_max_filesize. Dalam praktiknya, sebaiknya dibuat sedikit lebih besar karena request multipart memiliki overhead.

Cara cek nilai aktif PHP

Anda bisa cek via CLI:

php -i | grep upload_max_filesize
php -i | grep post_max_size

Namun hati-hati: nilai CLI belum tentu sama dengan PHP-FPM yang dipakai web server. Cara yang lebih aman adalah membuat halaman debug sementara atau endpoint internal yang menampilkan nilai ini_get().

Contoh sederhana di route sementara Laravel:

Route::get('/debug/php-upload-limits', function () {
    return response()->json([
        'upload_max_filesize' => ini_get('upload_max_filesize'),
        'post_max_size' => ini_get('post_max_size'),
        'memory_limit' => ini_get('memory_limit'),
    ]);
});

Contoh pengaturan di php.ini atau pool PHP-FPM:

upload_max_filesize = 10M
post_max_size = 12M
memory_limit = 256M

Setelah perubahan, restart PHP-FPM sesuai versi yang digunakan, misalnya:

sudo systemctl restart php8.2-fpm

Kenapa dua nilai ini penting? Jika file 8 MB dikirim tetapi upload_max_filesize hanya 2 MB, PHP akan menolak file tersebut. Jika total body request lebih besar dari post_max_size, data POST bisa kosong atau tidak lengkap. Hasilnya bisa terlihat seperti validasi gagal, input file null, atau request aneh meskipun di browser tampak hanya “upload gagal”.

Catatan tentang memory_limit

memory_limit bukan penyebab utama 413, tetapi tetap relevan jika setelah upload Anda melakukan manipulasi gambar, misalnya resize atau generate thumbnail. File yang lolos upload belum tentu bisa diproses jika memori terlalu kecil.

Validasi Laravel: Jangan Sampai Rule Aplikasi Justru Terlalu Ketat

Setelah request berhasil melewati web server dan PHP, barulah Laravel menjalankan validasi. Pada tahap ini, error yang muncul biasanya bukan lagi 413, melainkan respons validasi seperti 422 atau redirect dengan pesan gagal.

Contoh rule yang umum dipakai:

$request->validate([
    'image' => ['required', 'image', 'mimes:jpg,jpeg,png,webp', 'max:5120'],
]);

Di Laravel, rule max:5120 untuk file berarti 5120 KB, yaitu sekitar 5 MB. Ini sering menjadi sumber kebingungan karena banyak developer mengira satuannya byte atau megabyte.

Menyelaraskan batas di semua lapisan

Misalnya Anda ingin mengizinkan upload gambar sampai 5 MB. Maka pengaturan yang lebih aman bisa seperti ini:

  • Nginx client_max_body_size 10M;
  • PHP upload_max_filesize = 8M
  • PHP post_max_size = 10M
  • Laravel max:5120

Kenapa tidak disamakan persis? Karena tiap lapisan memiliki konteks berbeda. Laravel mengatur batas bisnis aplikasi, sedangkan Nginx dan PHP perlu sedikit ruang agar request multipart dapat lewat dengan wajar. Dengan pola ini, server tidak terlalu sempit, tetapi aplikasi tetap menegakkan batas final yang jelas.

Contoh Form Request yang lebih rapi

public function rules(): array
{
    return [
        'image' => [
            'required',
            'file',
            'image',
            'mimes:jpg,jpeg,png,webp',
            'max:5120',
        ],
    ];
}

public function messages(): array
{
    return [
        'image.max' => 'Ukuran gambar maksimal 5 MB.',
        'image.image' => 'File yang diunggah harus berupa gambar yang valid.',
    ];
}

Ini membantu pengguna mendapatkan pesan error yang jelas jika file terlalu besar di level aplikasi.

Studi Kasus Singkat: File 6 MB Gagal Upload

Misalkan ada kasus berikut:

  • Upload gambar 1 MB berhasil.
  • Upload gambar 6 MB gagal.
  • Frontend menerima status 413.
  • Laravel tidak mencatat error validasi.

Dari gejala ini, kemungkinan besar request ditolak sebelum masuk Laravel. Langkah diagnosis cepat:

  1. Cek Nginx: ternyata client_max_body_size 2M.
  2. Ubah ke 10M, reload Nginx.
  3. Uji lagi: sekarang status bukan 413, tetapi validasi Laravel gagal.
  4. Cek rule: ternyata max:2048 atau 2 MB.
  5. Sesuaikan rule ke max:5120 jika ingin 5 MB, atau ke angka lain sesuai kebutuhan bisnis.

Kasus ini menunjukkan bahwa sering ada lebih dari satu bottleneck. Setelah lapisan pertama diperbaiki, hambatan berikutnya baru terlihat.

Tips Verifikasi Setelah Deploy

Jangan berhenti setelah mengubah konfigurasi. Lakukan verifikasi nyata agar perubahan benar-benar aktif.

1. Uji beberapa ukuran file

Siapkan file gambar kecil, sedang, dan besar, misalnya 500 KB, 3 MB, 6 MB, dan 11 MB. Dengan begitu Anda tahu batas efektif yang sedang berlaku.

2. Cek respons status code

  • 413: biasanya ditolak web server
  • 422 atau redirect validasi: ditolak Laravel
  • 200/201: upload berhasil

3. Periksa log yang tepat

  • Nginx: /var/log/nginx/error.log
  • Apache: error log virtual host atau global
  • Laravel: storage/logs/laravel.log

Jika 413 berasal dari Nginx, biasanya ada petunjuk yang mengarah ke ukuran request body.

4. Pastikan environment yang diubah memang production yang aktif

Pada server dengan Docker, Kubernetes, atau multi-container, perubahan php.ini di host belum tentu berdampak ke container yang sebenarnya melayani request. Begitu juga pada managed hosting, ada kemungkinan setting harus diubah dari panel atau image container, bukan langsung di filesystem host.

5. Hapus endpoint debug setelah selesai

Jika Anda menambahkan route untuk menampilkan ini_get(), hapus setelah verifikasi. Jangan biarkan endpoint internal semacam itu terbuka di production.

Kesalahan yang Paling Sering Terjadi

  • Langsung menyalahkan Laravel padahal request belum sampai aplikasi.
  • Mengubah upload_max_filesize tetapi lupa menaikkan post_max_size.
  • Mengubah konfigurasi tapi lupa restart atau reload service.
  • Mengira rule Laravel max dihitung dalam MB, padahal untuk file satuannya KB.
  • Menguji lewat CLI dan menganggap nilainya sama dengan PHP-FPM.
  • Menetapkan batas terlalu longgar tanpa alasan bisnis yang jelas.

Rekomendasi Nilai Praktis

Untuk fitur upload gambar umum pada aplikasi web, pendekatan berikut cukup aman sebagai titik awal:

  • Laravel maksimal 5 MB per gambar
  • PHP upload_max_filesize 8 MB
  • PHP post_max_size 10 MB
  • Nginx client_max_body_size 10 MB atau sedikit di atas kebutuhan

Jika aplikasi mendukung beberapa file sekaligus, Anda perlu menghitung ulang post_max_size dan mungkin membedakan batas per file versus total request.

Penutup

Error 413 Request Entity Too Large saat upload gambar di Laravel hampir selalu dapat dipecahkan dengan pendekatan berlapis. Mulailah dari Nginx atau Apache, lanjut ke PHP-FPM lewat upload_max_filesize dan post_max_size, lalu pastikan validasi Laravel sesuai kebutuhan bisnis aplikasi. Dengan urutan cek yang benar, Anda tidak perlu menebak-nebak sumber masalah.

Jika ingin menemukan akar masalah dengan cepat, ingat aturan sederhana ini: 413 biasanya berarti request ditolak sebelum masuk Laravel. Setelah server dan PHP sudah benar, barulah Anda menyempurnakan rule validasi agar batas upload konsisten, aman, dan mudah dipahami pengguna.