In Laravel, why does an oversized upload fail with a 413 PostTooLargeException before any validation rule runs?
answer
- a global middleware, before routing
- compares Content-Length with post_max_size
- understands K, M and G suffixes
- PostTooLargeException is an HttpException(413)
- the max rule never gets a chance
basics
~10 sThe global ValidatePostSize middleware compares the request's Content-Length with PHP's post_max_size and throws PostTooLargeException, an HTTP 413, when it is larger. It runs before routing, so validation rules such as max never execute.
solid answer
~40 s`Illuminate\Http\Middleware\ValidatePostSize` sits on the default global stack. It reads `post_max_size` from PHP's ini settings, converting a `K`, `M` or `G` suffix into bytes, and if that limit is above zero and the request's `CONTENT_LENGTH` exceeds it, it throws `Illuminate\Http\Exceptions\PostTooLargeException` with the message `The POST data is too large.`. That exception extends `HttpException` with status 413. Because the global stack runs before the router, the controller, the form request and its `max:` rule never run, so the user sees a 413 page or JSON error instead of a validation message. The fix is to raise `post_max_size` (and `upload_max_filesize`) in PHP's configuration to sit above the largest upload you validate, so that your own `max` rule becomes the effective limit and produces a friendly message.
code
ini · 3 lines; php.ini - let the validator, not PHP, be the effective limit
upload_max_filesize = 8M
post_max_size = 10Mgo deeper
Recall that a body larger than PHP's post_max_size is rejected by a global middleware with a 413 before your code runs.
Explain the Content-Length comparison, the unit parsing and why the validator never gets a chance.
Align web server, PHP and validation limits so the friendly validation message is what users actually see.
Decide where upload limits are owned and documented across infrastructure and application layers, so one change does not silently shadow another.
## The symptom A voting app lets poll creators attach a banner image. Validation says `'banner' => 'image|max:4096'`, a 4 MB limit with a friendly error. A user uploads a 30 MB photo and gets a bare **413 Content Too Large** error, or a `PostTooLargeException` in development, with no validation message. The controller was never called. ## What ValidatePostSize does `Illuminate\Http\Middleware\ValidatePostSize` is part of Laravel's **default global middleware stack**, so it runs for every request before routing. Its logic is short: 1. Read PHP's `post_max_size` setting with `ini_get()`. 2. Convert it to bytes: a plain number is bytes; a trailing `K`, `M` or `G` multiplies by 1024, 1024^2 or 1024^3. 3. If the limit is greater than zero and the request's `CONTENT_LENGTH` server value is larger, throw `Illuminate\Http\Exceptions\PostTooLargeException('The POST data is too large.')`. 4. Otherwise pass the request on. `PostTooLargeException` extends Symfony's `HttpException` with status code **413**. Laravel's exception handler renders it like any other HTTP exception: an error page for browsers, a JSON error for clients that expect JSON. ## Why validation never runs Global middleware runs before the router matches a route. The request never reaches the route's middleware, the form request or the controller, so nothing that would evaluate `max:4096` gets a chance. This is intentional: when a body exceeds `post_max_size`, PHP itself discards the POST data, so `$_POST` and `$_FILES` would be empty anyway, and a validator would report confusing "field is required" errors instead of the real cause. ## Fixing it properly The goal is to make **your** limit the one users hit: | Setting | Role | Rule of thumb | |---|---|---| | `upload_max_filesize` (php.ini) | Largest single uploaded file PHP accepts | Above your largest `max:` rule | | `post_max_size` (php.ini) | Largest whole request body PHP accepts | Above `upload_max_filesize`, plus room for other fields | | Web server body limit | Largest body the server forwards | At least `post_max_size` | | `max:` validation rule | The limit users see with a friendly message | The real business limit | With those in order, a 30 MB photo is still rejected, but by the validator, with the message your form already knows how to display. Additional points: - `ValidatePostSize` checks the declared `Content-Length`. A request without one, such as some chunked uploads, is not rejected by this check. - Setting `post_max_size = 0` disables PHP's limit, and the middleware's check is skipped because the limit is not above zero. - The web server in front of PHP may reject the body with its own 413 before Laravel is involved; the response then comes from the server, not from Laravel. ## Debugging checklist 1. Compare the failing upload's size with `ini_get('post_max_size')` on the server that handled it; CLI and web PHP often load different ini files, so check from a web request. 2. If the response is a plain server error page rather than Laravel's, the web server rejected the body before PHP. 3. If Laravel's 413 appears, raise `post_max_size` and `upload_max_filesize` together and reload PHP. 4. If the request reached the controller but the file is missing or invalid, `upload_max_filesize` alone was probably exceeded; PHP reports that through the upload's error code, not through this middleware. ## Handling it gracefully If you would rather send users back to the form than show an error page, the exception can be rendered specially in `bootstrap/app.php` through `withExceptions()`, for example redirecting back with a flash message when `PostTooLargeException` is thrown. Removing `ValidatePostSize` from the global stack is not a fix: PHP still empties the POST data, and the app would then fail in more confusing ways.
- Why does removing ValidatePostSize from Laravel's global stack not let oversized uploads reach the validator?When a body exceeds `post_max_size`, PHP discards the POST data and files before Laravel runs. Without the middleware the request reaches the controller with empty input, so validation reports missing fields instead of the real problem. The middleware exists to fail fast with the correct 413.
- How would you show a friendly message instead of a 413 page for PostTooLargeException?Register a renderer for the exception in `bootstrap/app.php` through `withExceptions()`, for instance returning a redirect back with a flash message. The exception still fires before routing, so the handler, not the form request, has to produce the friendly response.
saying these in an interview costs you the question
- Expects the max validation rule to catch a body above post_max_size
- Removes ValidatePostSize to make large uploads work
- Raises the max rule without touching PHP's ini limits
- Thinks PostTooLargeException is thrown by the validator
- Believes the middleware inspects each uploaded file's size