mattermost-community/focalboard · error

cannot get direct channel: %w

Error message

cannot get direct channel: %w

What it means

getDirectChannelID wraps the failure of pd.getDirectChannel when resolving the direct-message channel between a subscriber and the delivery bot. Note the bug-prone shape: if getDirectChannel returns (nil, nil) — a nil channel with no error — the %w wraps a nil err, producing an error with a trailing empty cause. It means either the bot could not be added to the team or the direct channel could not be found/created in Mattermost.

Source

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

		ChannelId: channelID,
	}

	mm_model.ParseSlackAttachment(post, attachments)

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

func (pd *PluginDelivery) getDirectChannelID(teamID string, subscriberID string, subscriberType model.SubscriberType, botID string) (string, error) {
	switch subscriberType {
	case model.SubTypeUser:
		user, err := pd.api.GetUserByID(subscriberID)
		if err != nil {
			return "", fmt.Errorf("cannot find user: %w", err)
		}
		channel, err := pd.getDirectChannel(teamID, user.Id, botID)
		if err != nil || channel == nil {
			return "", fmt.Errorf("cannot get direct channel: %w", err)
		}
		return channel.Id, nil
	case model.SubTypeChannel:
		return subscriberID, nil
	default:
		return "", ErrUnsupportedSubscriberType
	}
}

func (pd *PluginDelivery) getDirectChannel(teamID string, userID string, botID string) (*mm_model.Channel, error) {
	// first ensure the bot is a member of the team.
	_, err := pd.api.CreateMember(teamID, botID)
	if err != nil {
		return nil, fmt.Errorf("cannot add bot to team %s: %w", teamID, err)
	}
	return pd.api.GetDirectChannelOrCreate(userID, botID)
}

View on GitHub (pinned to a84bbb65e3)

Solutions

  1. Verify the bot account exists, is active, and has permission to be added as a team member.
  2. Check the subscriber record points to a valid Mattermost user ID in the target team.
  3. Inspect the wrapped cause (%w) from the Mattermost API logs to see whether CreateMember or GetDirectChannelOrCreate failed.
  4. Fix the nil-channel nil-error case by returning an explicit error when channel == nil instead of wrapping a nil err.

Example fix

// before
channel, err := pd.getDirectChannel(teamID, user.Id, botID)
if err != nil || channel == nil {
	return "", fmt.Errorf("cannot get direct channel: %w", err)
}
// after
channel, err := pd.getDirectChannel(teamID, user.Id, botID)
if err != nil {
	return "", fmt.Errorf("cannot get direct channel: %w", err)
}
if channel == nil {
	return "", fmt.Errorf("cannot get direct channel for user %s: channel is nil", user.Id)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before delivering, verify subscriber user exists (plugin API)
u, err := api.GetUserByID(subscriberID)
if err != nil || u == nil || u.DeleteAt != 0 {
	// skip/queue this subscriber instead of attempting delivery
}

Type guard

func validChannel(c *mm_model.Channel) bool { return c != nil && c.Id != "" }

Try / catch

chID, err := getDirectChannelID(teamID, subscriberID, botID)
if err != nil {
	var nilCh *NilChannelError
	if errors.As(err, &nilCh) || strings.Contains(err.Error(), "cannot get direct channel") {
		logger.Warn("skipping DM subscriber", "subscriber", subscriberID, "cause", err)
		return // degrade gracefully, don't fail whole delivery
	}
	return err
}

Prevention

When it happens

Trigger: SubscriptionDeliverSlackAttachments resolves a subscriber of type DirectMessage; pd.api.CreateMember(teamID, botID) fails, or pd.api.GetDirectChannelOrCreate(userID, botID) fails, or returns nil channel with nil error.

Common situations: Bot user is deleted or deactivated; bot lacks permission to join the team; subscriber ID refers to a stale/deleted user (though that fails earlier with 'cannot find user'); Mattermost API connectivity/permission problems in the plugin.

Related errors


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