Skip to content

fix(user): retry group avatar fetch with IsCommunity on failure#78

Open
diwberg wants to merge 2 commits into
evolution-foundation:mainfrom
diwberg:fix/group-avatar-community-fallback
Open

fix(user): retry group avatar fetch with IsCommunity on failure#78
diwberg wants to merge 2 commits into
evolution-foundation:mainfrom
diwberg:fix/group-avatar-community-fallback

Conversation

@diwberg

@diwberg diwberg commented Jun 10, 2026

Copy link
Copy Markdown

Problem

POST /user/avatar always returns 500 when the number is a group JID (…@g.us).

GetAvatar calls whatsmeow's GetProfilePictureInfo with only Preview set. For group/community JIDs the regular w:profile:picture query is rejected by WhatsApp with 401 not-authorized, which surfaces as a 500 to the API consumer. whatsmeow itself documents this in GetProfilePictureParams: "To get a community photo, you should pass IsCommunity: true, as otherwise you may get a 401 error."

Reproduced live:

POST /user/avatar {"number":"120363044414041265@g.us","preview":false}
→ 401 {"error":"not authorized"}

Fix

When the first GetProfilePictureInfo attempt fails and the JID server is g.us, retry once with IsCommunity: true. Regular user JIDs are untouched — same single call as before.

if err != nil && jid.Server == types.GroupServer {
    pic, err = client.GetProfilePictureInfo(ctx, jid, &whatsmeow.GetProfilePictureParams{
        Preview:     data.Preview,
        IsCommunity: true,
    })
}

Testing

  • go build ./pkg/... clean.
  • Verified against a live instance: group JIDs that previously returned 500/401 now return the picture payload (url, id, type, direct_path); user JIDs unchanged.

Summary by Sourcery

Bug Fixes:

  • Fix group JID avatar requests that previously failed with authorization errors by retrying the lookup using community avatar parameters.

GetProfilePictureInfo rejects group/community JIDs on the regular
w:profile:picture query (401 not-authorized), so POST /user/avatar always
returned 500 for @g.us numbers. When the first attempt fails for a group
JID, retry with IsCommunity: true — the variant whatsmeow documents for
community photos. No behavior change for regular user JIDs.
@sourcery-ai

sourcery-ai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Adds a retry path for fetching WhatsApp group/community avatars: if the initial GetProfilePictureInfo call fails for a group JID, the service logs the failure and retries once using the IsCommunity flag, keeping behavior unchanged for regular user JIDs.

Sequence diagram for GetAvatar group retry with IsCommunity

sequenceDiagram
    participant ApiClient
    participant UserService
    participant WhatsmeowClient
    participant Logger

    ApiClient->>UserService: GetAvatar(data, instance)
    UserService->>WhatsmeowClient: GetProfilePictureInfo(ctx, jid, GetProfilePictureParams{Preview})
    alt first_call_error_and_group_jid
        WhatsmeowClient-->>UserService: error
        UserService->>Logger: LogInfo("GetProfilePictureInfo failed for group JID, retrying with IsCommunity")
        UserService->>WhatsmeowClient: GetProfilePictureInfo(ctx, jid, GetProfilePictureParams{Preview, IsCommunity})
        alt retry_error
            WhatsmeowClient-->>UserService: error
            UserService->>Logger: LogError("GetProfilePictureInfo failed")
            UserService-->>ApiClient: error
        else retry_success
            WhatsmeowClient-->>UserService: pic
            UserService-->>ApiClient: pic
        end
    else first_call_ok_or_non_group_jid
        WhatsmeowClient-->>UserService: pic_or_error
        alt error
            UserService->>Logger: LogError("GetProfilePictureInfo failed")
            UserService-->>ApiClient: error
        else success
            UserService-->>ApiClient: pic
        end
    end
Loading

File-Level Changes

Change Details Files
Add a conditional retry using the community avatar endpoint when fetching profile pictures for group JIDs fails.
  • Keep the existing GetProfilePictureInfo call with Preview based on request data
  • Detect failures combined with group JIDs by checking both a non-nil error and jid.Server == types.GroupServer
  • Log an informational message when the initial group avatar fetch fails, including instance ID and error details
  • Retry GetProfilePictureInfo with the same Preview setting but with IsCommunity set to true
  • Preserve the existing error logging and return behavior if the retry also fails
pkg/user/service/user_service.go

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • The retry path currently triggers for any error on group JIDs; consider restricting the retry to known authorization/not-authorized error types to avoid masking or duplicating unrelated failures.
  • You call u.loggerWrapper.GetLogger(instance.Id) twice in quick succession; consider storing the logger in a local variable to avoid repeated lookups and keep the logging code consistent.
  • The informational log on the first failure plus the error log on the final failure may produce noisy logs for persistent errors; consider lowering the first message to a more verbose level or only logging on the final outcome.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The retry path currently triggers for any error on group JIDs; consider restricting the retry to known authorization/not-authorized error types to avoid masking or duplicating unrelated failures.
- You call `u.loggerWrapper.GetLogger(instance.Id)` twice in quick succession; consider storing the logger in a local variable to avoid repeated lookups and keep the logging code consistent.
- The informational log on the first failure plus the error log on the final failure may produce noisy logs for persistent errors; consider lowering the first message to a more verbose level or only logging on the final outcome.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

…ogging

Review feedback: retry only on whatsmeow.ErrProfilePictureUnauthorized (the
documented community case) instead of any error, so unrelated failures
surface unchanged; hoist the per-instance logger into a local; demote the
pre-retry message to debug so persistent failures log a single error.
@diwberg

diwberg commented Jun 10, 2026

Copy link
Copy Markdown
Author

Addressed the review in a112370: the retry is now scoped to whatsmeow.ErrProfilePictureUnauthorized (checked via errors.Is, which the wrappedIQError.Is implementation supports), the per-instance logger is hoisted into a local across GetAvatar, and the pre-retry message was demoted to debug so persistent failures produce a single error log.

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.

1 participant