Skip to content

Laravel error

Laravel: Add [field] to fillable to allow mass assignment

The error

Add [role] to fillable property to allow mass assignment on [App\Models\User].

The MassAssignmentException is a security guard, not an obstacle. What it is protecting you from, the right fix, and why $guarded = [] is the wrong one.

The error

Illuminate\Database\Eloquent\MassAssignmentException

Add [role] to fillable property to allow mass assignment on [App\Models\User].

What it means

You called create(), fill() or update() with an array containing a key that the model does not allow to be filled in bulk.

User::create($request->all());   // $request->all() contains 'role'

Eloquent refuses. That refusal is the point: mass assignment is the vulnerability where an attacker adds a field to a form post that your code never intended to accept, and the model writes it because it was in the array.

POST /register
name=Ada&email=ada@example.com&password=...&role=admin

Without the guard, that request creates an administrator. With it, it throws. The exception is the framework telling you that an unvetted array reached a model.

The fix

List the fields that may be filled from input:

class User extends Model
{
    protected $fillable = ['name', 'email', 'password'];
}

role is deliberately absent. Setting it stays an explicit act:

$user = User::create($request->validated());
 
$user->role = 'admin';   // direct assignment bypasses fillable, by design
$user->save();

And pass validated input rather than raw input:

User::create($request->validated());   // only the keys your rules named
// not
User::create($request->all());         // every key the client chose to send

validated() returns only the keys your rules covered, which removes the whole class of problem before it reaches the model. Where you need a subset, $request->only([...]) is the explicit version.

What looks like a fix and is not

protected $guarded = []; This is the answer at the top of most search results and it disables mass assignment protection entirely for that model. Every column becomes fillable, including id, role, is_admin, email_verified_at and whatever you add next year. The exception goes away and so does the guard that produced it.

Adding the field to $fillable without thinking about it. If the error names role, is_admin or account_balance, the framework has just told you that user input is reaching a field that should never come from user input. The fix is upstream - stop passing that key - not to widen the allow-list until the error stops.

Switching to forceFill(). It works and it means "I am sure", which is fine for a seeder or an internal command and wrong for anything holding a request payload.

The habit that prevents it

Type your input at the boundary: a form request whose rules name every field you accept, and validated() everywhere you would have written all(). Then $fillable is a second line of defence rather than the only one, and this exception becomes something you see once, in development, on the day you add a column.

A $fillable entry that decides permissions is the expensive version of this, and it is one of the omissions an audit goes looking for. Mass assignment is where authorisation and validation get mistaken for each other.

Related questions

Is $guarded = [] ever acceptable?
On a model no request payload ever reaches - an internal pivot, a log table written only by your own code - the risk is theoretical. The trouble is that the model which is internal today is the one exposed by an import feature next year, and nobody revisits the decision. Listing fillable fields costs one line.
Why did this work in the tutorial?
Because the tutorial used $guarded = [] or created the record field by field. Both are common in teaching material, where the point is the feature rather than the boundary.
Does validation not already protect me?
Only if your validation rejects unknown keys, and by default it does not - it validates the keys you named and ignores the rest. A form request that validates name and email will happily pass an is_admin through to create().
Call us+1 848 272 7583WhatsApp+90 850 308 5436Emailinfo@codefacture.comContact page