chenhg5/cc-connect · error

discord: invalid session key %q

Error message

discord: invalid session key %q

What it means

Session keys in this codebase are namespaced strings of the form "discord:<channelID>[:threadID]". parseDiscordSessionKeyChannelID rejects any key whose first segment is not "discord" or whose channel segment is empty. resolveCronReplyTarget hits this when handed a session key that does not belong to the Discord platform or is malformed.

Source

Thrown at platform/discord/discord.go:327

	}
	return truncateDiscordThreadName(name, 90)
}

func standaloneThreadType(parentType discordgo.ChannelType) (discordgo.ChannelType, bool) {
	switch parentType {
	case discordgo.ChannelTypeGuildText:
		return discordgo.ChannelTypeGuildPublicThread, true
	case discordgo.ChannelTypeGuildNews:
		return discordgo.ChannelTypeGuildNewsThread, true
	default:
		return 0, false
	}
}

func parseDiscordSessionKeyChannelID(sessionKey string) (string, error) {
	parts := strings.SplitN(sessionKey, ":", 3)
	if len(parts) < 2 || parts[0] != "discord" || parts[1] == "" {
		return "", fmt.Errorf("discord: invalid session key %q", sessionKey)
	}
	return parts[1], nil
}

func resolveSessionKeyForChannel(channelID, userID string, shareSessionInChannel bool, threadIsolation bool, ops discordThreadOps) string {
	if !threadIsolation {
		return buildSessionKey(channelID, userID, shareSessionInChannel)
	}
	ch, err := ops.ResolveChannel(channelID)
	if err != nil {
		slog.Warn("discord: resolve channel for session key failed, falling back", "channel", channelID, "error", err)
		return buildSessionKey(channelID, userID, shareSessionInChannel)
	}
	if isThreadChannelType(ch.Type) {
		return buildThreadSessionKey(channelID)
	}
	return buildSessionKey(channelID, userID, shareSessionInChannel)
}

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Fix the cron job's sessionKey so it is "discord:<channelID>" with a non-empty channel ID.
  2. Validate session keys at config-load time before scheduling the cron job.
  3. If the key came from persisted state, re-create the cron job from a live Discord session so the key is regenerated correctly.
  4. Check that the cron target belongs to this Discord platform instance, not another platform's agent session.

Example fix

// before
[agent.cron]
sessionKey = "feishu:ou_123"   # wrong platform
// after
[agent.cron]
sessionKey = "discord:123456789012345678"
Defensive patterns

Strategy: validation

Validate before calling

func validDiscordSessionKey(k string) bool {
    parts := strings.SplitN(k, ":", 3)
    return len(parts) >= 2 && parts[0] == "discord" && parts[1] != ""
}
// before scheduling: if !validDiscordSessionKey(cfg.SessionKey) { reject }

Try / catch

chID, err := parseDiscordSessionKeyChannelKey(key)
if err != nil {
    return fmt.Errorf("cron target is not a Discord session key: %w", err)
}

Prevention

When it happens

Trigger: resolveCronReplyTarget receives a sessionKey from config or stored state that is empty, missing the "discord:" prefix, or has an empty channel ID — e.g. a cron job saved under a Telegram/Feishu session key or written by an older format.

Common situations: Cron job config pointing at the wrong platform's session, hand-edited config.toml session keys, stale persisted session keys from a pre-thread-isolation format, or copy-pasted keys across platform configs.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/91f418899a22b1db. Report an issue: GitHub.