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 sendvalidated() 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.
