Back to Blog
4 min read

How We Fixed Null-Safety Bugs in Laravel User Models (And Made Our Admin Panel More Resilient)

The Silent Killer in Our Admin Panel

Last week, our Laravel app serving Capital City’s admin panel started throwing 500 errors—intermittent, frustrating, and always pointing back to user data. The culprit? null values sneaking into places we assumed were safe. We had models returning null->name, null->url, and even trying to call methods on non-existent relationships. These weren’t edge cases—they were real users with incomplete profiles, and our code wasn’t ready.

It’s easy to assume that every user will have a name or an avatar. But in production, data is messy. A user signs up with a social account that returns no name. Another deletes their avatar but still appears in the admin. Without null safety, one missing field can bring down an entire page.

We decided to stop treating null like a bug and start handling it like a feature.

Fixing the Display Name: A Simple Fallback That Prevents Chaos

One of the most common crashes came from the getDisplayNameAttribute() method in our User model. We wanted to show a clean name in the admin panel—either the user’s first and last name, or their email if names weren’t set. But our original code looked like this:

public function getDisplayNameAttribute()
{
    return $this->first_name . ' ' . $this->last_name;
}

What happens if first_name is null? PHP happily converts it to an empty string—but if both are null, you get a trailing space or, worse, a concatenation error in strict contexts. And if one is missing? You get "John " or " Smith", which looks unprofessional.

The fix was simple but powerful. We added a null-coalescing fallback:

public function getDisplayNameAttribute()
{
    if ($this->first_name || $this->last_name) {
        return trim("{$this->first_name} {$this->last_name}");
    }

    return $this->email ?? 'Unknown User';
}

This one change—backed by the commit 'fixed null name attribute'—eliminated a whole class of display errors. Now, even if a user has no name, the admin panel shows their email or a safe default. No more 500s. No more blank labels.

Null-Safe Avatar Access: Because Not Everyone Has a Profile Picture

The second major crash point was the avatar. Our admin UI tried to display a user’s avatar using a relationship:

<img src="{{ $user->avatar->url }}" />

But what if the user never uploaded one? $user->avatar returns null, and calling ->url on it throws a fatal error. This wasn’t just a visual issue—it crashed the entire page.

The commit 'trying to fix avatar 500 error' addressed this head-on. We didn’t want to add complex checks in every Blade template. Instead, we made the model itself resilient.

We updated the accessor:

public function getAvatarUrlAttribute()
{
    return $this->avatar?->url ?? '/images/default-avatar.png';
}

That ?-> is PHP’s null-safe operator—available in PHP 8.0+, and a game-changer. If avatar is null, the chain stops cleanly and returns null, which we then fallback with a default image.

Now, in Blade, we can safely write:

<img src="{{ $user->avatar_url }}" alt="Profile Picture" />

No conditionals. No exceptions. Just resilience.

We also extended this pattern to other optional relationships—like user roles or metadata—ensuring that a missing piece of data doesn’t derail the entire experience.

Why This Matters for Real Admin Panels

These fixes might seem small, but their impact was immediate. The admin panel, built with Filament PHP, went from flaky to rock-solid. Users (the admins, not the end-users) stopped seeing error pages and started trusting the system again.

More importantly, we shifted our mindset. Instead of writing code that assumes data exists, we’re now writing code that survives its absence. That’s the difference between a prototype and a production-ready app.

If you’re building Laravel apps with Filament—and especially if you’re showing user data in tables, forms, or profiles—don’t wait for the 500s to hit. Audit your accessors. Use the null-safe operator. Add fallbacks. Treat null like the first-class citizen it is in real-world data.

Because in the end, resilience isn’t about perfect data. It’s about graceful degradation when things go wrong. And that’s exactly what we built.

Newer post

How We Built a Unified Search Across Services, Products, and Templates in Next.js

Older post

How We Fixed Form Submissions in Filament PHP with Dynamic Field Handling