mattermost-community/focalboard · error

cannot fetch channel member for user %s: %w

Error message

cannot fetch channel member for user %s: %w

What it means

SubscriptionDeliverSlackAttachments returns this error when verifying the subscriber via GetUserByID fails with an error other than not-found (not-found subscribers are silently skipped). The wrapped error indicates the subscriber's user record could not be retrieved from the Mattermost plugin API, so the subscription notification cannot be delivered. Note the message says 'channel member' but the actual call is a user lookup — the naming is misleading.

Source

Thrown at server/services/notify/plugindelivery/subscription_deliver.go:29

	mm_model "github.com/mattermost/mattermost/server/public/model"
)

var (
	ErrUnsupportedSubscriberType = errors.New("invalid subscriber type")
)

// SubscriptionDeliverSlashAttachments notifies a user that changes were made to a block they are subscribed to.
func (pd *PluginDelivery) SubscriptionDeliverSlackAttachments(teamID string, subscriberID string, subscriptionType model.SubscriberType,
	attachments []*mm_model.SlackAttachment) error {
	// check subscriber is member of channel
	_, err := pd.api.GetUserByID(subscriberID)
	if err != nil {
		if model.IsErrNotFound(err) {
			// subscriber is not a member of the channel; fail silently.
			return nil
		}
		return fmt.Errorf("cannot fetch channel member for user %s: %w", subscriberID, err)
	}

	channelID, err := pd.getDirectChannelID(teamID, subscriberID, subscriptionType, pd.botID)
	if err != nil {
		return err
	}

	post := &mm_model.Post{
		UserId:    pd.botID,
		ChannelId: channelID,
	}

	mm_model.ParseSlackAttachment(post, attachments)

	_, err = pd.api.CreatePost(post)
	return err
}

View on GitHub (pinned to a84bbb65e3)

Solutions

  1. Check the wrapped cause to distinguish transient API errors from persistent user problems
  2. Clean up subscription records referencing deleted users
  3. Retry delivery on transient plugin API failures
  4. Verify plugin API connectivity and bot permissions

Example fix

// before
if _, err := pd.api.GetUserByID(subscriberID); err != nil {
	return fmt.Errorf("cannot fetch channel member for user %s: %w", subscriberID, err)
}
// after
if _, err := pd.api.GetUserByID(subscriberID); err != nil {
	if model.IsErrNotFound(err) {
		return nil
	}
	if errors.Is(err, context.DeadlineExceeded) {
		return err // transient; safe to retry
	}
	return fmt.Errorf("cannot fetch channel member for user %s: %w", subscriberID, err)
}
Defensive patterns

Strategy: validation

Validate before calling

// prune subscriptions pointing at deleted users before delivery runs
subs, err := appAPI.GetSubscribersForBlock(blockID)
if err != nil {
	return err
}
for _, s := range subs {
	if _, err := pd.api.GetUserByID(s.UserID); err != nil {
		// remove or skip this subscription
	}
}

Type guard

func subscriberExists(api UserAPI, subscriberID string) bool {
	_, err := api.GetUserByID(subscriberID)
	return err == nil
}

Try / catch

err := pd.SubscriptionDeliverSlackAttachments(evt, subscriptionType, subscriberID, extract)
if err != nil {
	if model.IsErrNotFound(err) {
		return nil // stale subscriber; drop
	}
	// transient API error: safe to retry
	return retryDelivery(evt, subscriberID)
}

Prevention

When it happens

Trigger: Delivering a slack-attachment style notification to a subscriber whose GetUserByID call fails for reasons other than ErrNotFound — plugin API unreachable, deactivated user treated as a hard error, transient server error, or invalid subscriber ID format.

Common situations: Mattermost server restarts while notification deliveries are queued; corrupted subscription records with stale user IDs; rate limiting or permission errors on the plugin API; partially deleted users (subscriptions not cleaned up).

Related errors


AI-assisted analysis of mattermost-community/focalboard@a84bbb65e3 (2026-08-30). Data as JSON: /api/errors/86c8c7cdbaa99113. Report an issue: GitHub.