Skip to content

Fix 500 when removing a profile picture - #96

Merged
HafizMMoaz merged 1 commit into
mainfrom
fix/94-profile-avatar-deletion
Jul 27, 2026
Merged

Fix 500 when removing a profile picture#96
HafizMMoaz merged 1 commit into
mainfrom
fix/94-profile-avatar-deletion

Conversation

@HafizMMoaz

Copy link
Copy Markdown
Member

Fixes #94.

Root cause

users.avatar is varchar(255) NOT NULL DEFAULT 'avatar.png'. Clearing the MediaPicker submits an empty string, and Laravel's ConvertEmptyStringsToNull turns that into null before it reaches validation, so ProfileController::update() saved a null into a NOT NULL column:

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'avatar' cannot be null

Hence the 500, the picture never being removed, and no message reaching the user. Reproduced directly against the column before fixing.

The old guard if ($user->wasChanged('avatar') && $user->avatar) also skipped the clear case, so even without the constraint error avatar_media_id would have stayed pointing at media that no longer represented the user, which is the part the issue's suggested fix covers.

Change

  • Clearing the avatar now falls back to the default placeholder instead of null. "No avatar" is avatar.png in this schema, never null, which is the convention AuthApiController and BackfillMediaAttachments already follow.
  • The media link is cleared as well as set, so removing a picture nulls avatar_media_id.
  • An update that omits avatar entirely still leaves the existing picture alone, since validated() only returns keys the request actually sent.
  • The placeholder value moves into User::DEFAULT_AVATAR alongside a hasCustomAvatar() helper, so the magic string is not spread further.
  • The profile form treats the placeholder as empty, so a user with no picture sees the placeholder icon and no clear button, instead of a clear button with nothing to clear.

Tests

New tests/Feature/ProfileAvatarTest.php, 4 tests / 13 assertions, all passing:

✓ avatar can be removed without a server error
✓ removing the avatar clears the media link
✓ an omitted avatar leaves the existing one alone
✓ the default placeholder does not count as a custom avatar

They live in their own file rather than in ProfileTest because ProfileTest is red on main for an unrelated reason: it uses RefreshDatabase with factory users that carry no permissions, so every request 403s on ProfileUpdateRequest::authorize()'s edit-profile check. These follow the DatabaseTransactions + explicit permission grant pattern that UserCreationTest uses and that does pass. Worth a separate issue.

npx tsc --noEmit is clean.

Clearing the avatar picker submits an empty string, which
ConvertEmptyStringsToNull hands to ProfileController as null. `users.avatar`
is NOT NULL with an `avatar.png` default, so saving that null raised an
integrity violation and the profile page returned a 500: the picture was
never removed and no error surfaced to the user.

Removing a picture now falls back to the default placeholder rather than
null, and the media link is cleared as well as set, so avatar_media_id no
longer keeps pointing at media that no longer represents the user. An update
that omits the avatar field entirely still leaves the existing picture alone.

The placeholder value moves into User::DEFAULT_AVATAR with a hasCustomAvatar()
helper, and the profile form treats it as empty so a user with no picture
sees the placeholder icon instead of a clear button with nothing to clear.
@HafizMMoaz
HafizMMoaz requested a review from a team as a code owner July 27, 2026 12:39
@HafizMMoaz
HafizMMoaz merged commit bdadfad into main Jul 27, 2026
1 check passed
@HafizMMoaz
HafizMMoaz deleted the fix/94-profile-avatar-deletion branch July 27, 2026 12:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Profile Picture Deletion Returns 500 Internal Server Error

1 participant