Skip to content

Story #2638 :: Missing profile image file causes a 500 on every page that renders an avatar - #2639

Draft
herzog0 wants to merge 3 commits into
developfrom
teo/profile-picture-validation-fix
Draft

Story #2638 :: Missing profile image file causes a 500 on every page that renders an avatar#2639
herzog0 wants to merge 3 commits into
developfrom
teo/profile-picture-validation-fix

Conversation

@herzog0

@herzog0 herzog0 commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Issue: #[number]

Summary & Context

A user whose profile_image row names a file that is not present in storage
caused a 500 on every page that rendered that user's avatar. This makes
User.get_thumbnail_url() degrade to None, so get_avatar_url() returns the
empty string and the template renders the coloured initials circle instead.

get_hq_image_url() had the identical defect against the hq_image field and is
fixed the same way, since the avatar template tag calls both methods on the same
render paths and either one raising is enough to take the page down.

  • Figma link: n/a - backend fix, no design change
  • Link to components/page: localhost:8000/ (homepage community post cards),
    any library page, any user profile page

Changes

  • users/models.py - widened the error handling in get_thumbnail_url() and
    get_hq_image_url() so a missing image file is caught instead of escaping. Both
    now return None and the avatar falls back to the initials circle.
  • users/tests/test_models.py - five tests covering both methods, with the file
    present and missing. First test coverage for either.

‼️ Risks & Considerations ‼️

Please list any potential risks or areas that need extra attention during review/testing

  • Widened suppression scope, in both methods. suppress now also covers
    AttributeError and OSError raised while evaluating self.profile_image /
    self.hq_image, not just the render's URL access. A genuinely broken storage
    backend will now yield a fallback avatar silently rather than erroring. That is
    the intent for the avatar case, but it does mean storage problems get quieter
    here.
  • get_hq_image_url() degrading to None changes which image renders, not
    just the status code.
    avatar_tags.py computes
    use_hq_image = use_user_hq_image and hq_image, so a caller that asked for the
    high-quality avatar now silently falls back to the standard thumbnail when the
    hq_image file is missing. That is the desired outcome, but it is a visual
    change on those call sites rather than a pure error fix.
  • No migration, no template change, no new dependency.

Screenshots

Before After
|

Peer-review testing steps

Automated

docker compose exec web python -m pytest users/tests/test_models.py -k "thumbnail or avatar or hq_image"

The three missing-file tests fail with FileNotFoundError against the unfixed
methods and pass with the fix applied. Verified in both directions, one method at
a time: reverting get_thumbnail_url() alone fails exactly
test_get_thumbnail_url_returns_none_when_file_missing and
test_get_avatar_url_falls_back_when_file_missing; reverting
get_hq_image_url() alone fails exactly
test_get_hq_image_url_returns_none_when_file_missing. In every case the
traceback is the one from the issue, raised out of
imagekit/specs/__init__.py generate().

users/tests/test_avatar_tags.py also passes unchanged, which covers the
template tag that calls both methods.

Note for anyone running the suite in a one-off container rather than the running
web service: DEBUG_TOOLBAR must be off, otherwise debug_toolbar.apps calls
MIGRATION_MODULES.setdefault() on the DisableMigrations stub in
config/test_settings.py and Django fails to boot.

Manual, page level

The setup requires a local database change, which is reverted at the end.

  1. Find a user whose avatar the homepage renders and note their id as
    AUTHOR_ID:

    docker compose exec web python manage.py shell -c "
    from news.models import Entry
    qs = Entry.objects.ranked().filter(deleted_at__isnull=True, published=True)
    for e in qs.select_related('author')[:5]:
        print(e.author_id, e.author.email, repr(e.author.profile_image.name))
    "
  2. Record the current value so it can be restored:

    SELECT profile_image FROM users_user WHERE id = AUTHOR_ID;
  3. Point the row at a file that does not exist:

    UPDATE users_user
    SET profile_image = 'profile-images/does-not-exist.png'
    WHERE id = AUTHOR_ID;
  4. On develop, confirm the failure. Method level raises
    FileNotFoundError: [Errno 2] No such file or directory: '/code/media/profile-images/does-not-exist.png'; page level returns 500:

    docker compose exec web python manage.py shell -c "
    from users.models import User
    print(User.objects.get(pk=AUTHOR_ID).get_thumbnail_url())
    "
    curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8000/
  5. On this branch, repeat step 4. Method level prints None with no exception;
    page level returns 200, and the affected author renders the coloured
    initials circle instead of an image. Check a library page and that user's
    profile page too.

  6. Restore the original value and re-run the method-level check. It should
    return the thumbnail URL again, confirming the happy path is untouched:

    UPDATE users_user SET profile_image = '<value from step 2>' WHERE id = AUTHOR_ID;
  7. Repeat steps 2 to 6 against hq_image instead of profile_image, on a user
    who has one. Only a page that renders the avatar with use_user_hq_image
    exercises this path, so it is easiest to confirm at the method level:

    SELECT id, hq_image FROM users_user WHERE hq_image IS NOT NULL AND hq_image != '';
    UPDATE users_user SET hq_image = 'hiqh-quality-user-images/nope.png' WHERE id = AUTHOR_ID;
    docker compose exec web python manage.py shell -c "
    from users.models import User
    print(User.objects.get(pk=AUTHOR_ID).get_hq_image_url())
    "

    Raises on develop, prints None on this branch. Restore the recorded value
    afterwards.

Self-review Checklist

  • Tag at least one team member from each team to review this PR
  • Link this PR to the related GitHub Project ticket

Backend

  • Black + Ruff clean (pre-commit run --files users/models.py users/tests/test_models.py)
  • Regression tests fail without the fix and pass with it
  • No migration required
  • Happy path unchanged for users whose file is present

@herzog0 herzog0 linked an issue Aug 19, 2026 that may be closed by this pull request
5 tasks
@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e8b3a37a-83e8-4d42-89c3-3f0d96df1450

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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.

Missing profile image file causes a 500 on every page that renders an avatar

1 participant