mattermost-community/focalboard · error

cannot notify block subscribers for block %s: %w

Error message

cannot notify block subscribers for block %s: %w

What it means

BlockChanged aggregates notification failures into a multi-error (merr). This entry is appended when notifySubscribers fails to trigger change notifications for a block's subscribers — i.e., writing the notification hint to the database failed. The block ID and modified-by user are included; the underlying error is wrapped with %w. The block change itself succeeded; only subscriber notification delivery failed.

Source

Thrown at server/services/notify/notifysubscriptions/subscriptions_backend.go:153

	}

	// notify card subscribers
	subs, err = b.appAPI.GetSubscribersForBlock(evt.Card.ID)
	if err != nil {
		merr.Append(fmt.Errorf("cannot fetch subscribers for card %s: %w", evt.Card.ID, err))
	}
	if err = b.notifySubscribers(subs, evt.Card.ID, model.TypeCard, evt.ModifiedBy.UserID); err != nil {
		merr.Append(fmt.Errorf("cannot notify card subscribers for card %s: %w", evt.Card.ID, err))
	}

	// notify block subscribers (if/when other types can be subscribed to)
	if evt.Board.ID != evt.BlockChanged.ID && evt.Card.ID != evt.BlockChanged.ID {
		subs, err := b.appAPI.GetSubscribersForBlock(evt.BlockChanged.ID)
		if err != nil {
			merr.Append(fmt.Errorf("cannot fetch subscribers for block %s: %w", evt.BlockChanged.ID, err))
		}
		if err := b.notifySubscribers(subs, evt.BlockChanged.ID, evt.BlockChanged.Type, evt.ModifiedBy.UserID); err != nil {
			merr.Append(fmt.Errorf("cannot notify block subscribers for block %s: %w", evt.BlockChanged.ID, err))
		}
	}
	return merr.ErrorOrNil()
}

// notifySubscribers triggers a change notification for subscribers by writing a notification hint to the database.
func (b *Backend) notifySubscribers(subs []*model.Subscriber, blockID string, idType model.BlockType, modifiedByID string) error {
	if len(subs) == 0 {
		return nil
	}

	hint := &model.NotificationHint{
		BlockType:    idType,
		BlockID:      blockID,
		ModifiedByID: modifiedByID,
	}

	hint, err := b.appAPI.UpsertNotificationHint(hint, b.getBlockUpdateFreq(idType))

View on GitHub (pinned to a84bbb65e3)

Solutions

  1. Check the wrapped cause (errors.As on the multi-error) for the underlying DB error from UpsertNotificationHint
  2. Verify database connectivity and the notification hints table health
  3. Re-trigger the block change or manually notify subscribers if delivery was lost
  4. Inspect notifySubscribers and onNotifyHint logs for the specific failing subscriber

Example fix

// before
if err := backend.BlockChanged(evt); err != nil {
	return err
}
// after
if err := backend.BlockChanged(evt); err != nil {
	var merr *model.MultiError
	if errors.As(err, &merr) {
		logger.Warn("partial notification failure", "errs", merr.Error())
	}
	return err
}
Defensive patterns

Strategy: type-guard

Type guard

func unwrapMultiErrors(err error) []error {
	var merr *model.MultiError
	if errors.As(err, &merr) {
		return merr.Errors
	}
	return []error{err}
}
func isNotifyHintFailure(err error) bool {
	for _, e := range unwrapMultiErrors(err) {
		if strings.Contains(e.Error(), "cannot notify block subscribers") {
			return true
		}
	}
	return false
}

Try / catch

if err := backend.BlockChanged(evt); err != nil {
	for _, e := range unwrapMultiErrors(err) {
		logger.Warn("block notification failure", "err", e)
	}
	// block change already succeeded; log and continue
}

Prevention

When it happens

Trigger: A block change event (card/view/board update) fires BlockChanged for a block that has subscribers, and notifySubscribers fails — typically because UpsertNotificationHint returns a database error, or the notifier callback fails on the hint.

Common situations: Database outages or write contention on the notifications table during heavy board activity; blocks with many subscribers causing hint-write contention; misconfigured notification storage in self-hosted deployments.

Related errors


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