max
Caps a field's size: characters, numeric value, array count or file kilobytes.
max:valueParameters
| Parameter | Type | Description |
|---|---|---|
$value | int|float | The maximum size, inclusive. Interpreted as characters for strings, the numeric value for numbers, the element count for arrays, or kilobytes for files. |
Errors
Nothing on its own; a failure surfaces as Illuminate\Validation\ValidationException when run through validate() or a form request.
The field under validation must be less than or equal to a maximum value. Strings, numerics, arrays and files are evaluated in the same fashion as the size rule, so the number you write means characters, magnitude, element count or kilobytes depending on what else is in the rule list.
The everyday use: matching your column
max:255 next to a string column is the most common rule in a Laravel codebase, and it exists for a real reason — MySQL in strict mode rejects an over-long insert with a database error rather than a friendly validation message. Keep the two numbers in sync when a migration changes.
The type trap, in reverse
Like min, max counts characters unless numeric or integer is also present. 'discount' => 'max:100' on form input accepts "99999999" quite happily, because that is only eight characters. Write 'discount' => 'numeric|max:100'.
Uploads fail before you see them
For files the unit is kilobytes, so max:2048 is 2 MB. But PHP's own upload_max_filesize and post_max_size reject an oversized request before the validator runs — you get an empty payload and a required error, not a size error. Raise those INI values above your validation ceiling.
Example
<?php
use Illuminate\Support\Facades\Validator;
$data = ['discount' => '99999999']; // eight characters, as posted
// No numeric rule: max counts the 8 characters, which is under 100.
var_dump(Validator::make($data, ['discount' => 'max:100'])->passes());
// With numeric, 99999999 is compared against 100.
var_dump(Validator::make($data, ['discount' => 'numeric|max:100'])->passes());
// bool(true) <- the silent bug
// bool(false)When to use it
- Keeping a title within the 255 characters its varchar column allows.
- Capping an uploaded avatar at 2 MB with max:2048.
- Limiting a discount percentage to 100 on a numeric input.
- Preventing a bulk endpoint from accepting more than 50 items in one array.
Frequently asked questions
Why does max:2048 not reject my 10 MB upload?
PHP rejected the request before Laravel saw it. When a POST exceeds `post_max_size` or `upload_max_filesize`, the file never reaches $_FILES, so the validator reports the field as missing rather than too large. Set those INI values comfortably above your max: rule.
Does max count bytes or characters for a string?
Characters — Laravel uses `mb_strlen`, so a 100-character Japanese string satisfies `max:100` despite occupying 300 bytes. This matches `varchar` semantics in MySQL and PostgreSQL, but not `text` columns, whose limits are byte-based.
Why is max:100 letting large numbers through?
Because without `numeric` or `integer` in the rule list, `max` measures the string's character count. "99999999" is eight characters, comfortably under 100. Write `numeric|max:100` so the value is compared as a number.
More examples
max across all four value types
All four fail, each for a different reason: 300 characters, the value 7, a count of 12, and a missing file caught by `required`. The `brochure` error is `required`, not `max` — another reminder that `max` is skipped entirely for absent values.
<?php
use Illuminate\Support\Facades\Validator;
$rules = [
'title' => ['required', 'string', 'max:255'],
'rating' => ['required', 'integer', 'max:5'],
'tags' => ['required', 'array', 'max:10'],
'brochure' => ['required', 'file', 'max:5120'], // 5 MB
];
$validator = Validator::make([
'title' => str_repeat('a', 300),
'rating' => 7,
'tags' => range(1, 12),
], $rules);
print_r($validator->errors()->keys());
// Array
// (
// [0] => title
// [1] => rating
// [2] => tags
// [3] => brochure
// )Keeping validation aligned with the schema
When the migration says 160 and the rule still says 255, MySQL in strict mode throws a QueryException on insert and the user sees a 500 rather than a form error. The `text` column's own limit of 65535 bytes is worth stating too, since multi-byte characters consume more than one byte each.
<?php
// database/migrations/..._create_posts_table.php
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title', 160); // <- the real ceiling
$table->text('body');
$table->timestamps();
});
// app/Http/Requests/StorePostRequest.php
public function rules(): array
{
return [
'title' => ['required', 'string', 'max:160'], // must match
'body' => ['required', 'string', 'max:65535'],
];
}
// echo strlen($request->validated()['title']); // <= 160Multi-byte strings count characters, not bytes
Laravel measures string length with `mb_strlen`, so 100 Japanese characters satisfy `max:100`. MySQL's `varchar(100)` also counts characters, so the two agree — but a `text` column's 65535 limit is measured in bytes, which is where a `max` rule tuned to character counts can still let an insert fail.
<?php
use Illuminate\Support\Facades\Validator;
$value = str_repeat('あ', 100); // 100 characters, 300 UTF-8 bytes
var_dump(mb_strlen($value));
var_dump(strlen($value));
var_dump(Validator::make(['bio' => $value], ['bio' => 'string|max:100'])->passes());
// int(100)
// int(300)
// bool(true)
Discussion