chenhg5/cc-connect · error

dingtalk: invalid session key format: %q

Error message

dingtalk: invalid session key format: %q

What it means

The session key had the 'dingtalk:' prefix but, after stripping it, contained fewer than 2 colon-separated segments. The expected format is 'dingtalk:{convType}:{conversationId}' optionally followed by ':{senderStaffId}' — at minimum convType and conversationId must be present. The key is therefore structurally malformed.

Source

Thrown at platform/dingtalk/dingtalk.go:1614

	if len(runes) <= maxQuotedMessageRunes {
		return text
	}
	return string(runes[:maxQuotedMessageRunes]) + "..."
}

// ReconstructReplyCtx implements core.ReplyContextReconstructor.
// Session key format: "dingtalk:{convType}:{conversationId}:{senderStaffId}" or "dingtalk:{convType}:{conversationId}"
// where convType is "g" (group) or "d" (direct/1:1).
func (p *Platform) ReconstructReplyCtx(sessionKey string) (any, error) {
	if !strings.HasPrefix(sessionKey, "dingtalk:") {
		return nil, fmt.Errorf("dingtalk: not a dingtalk session key: %q", sessionKey)
	}

	stripped := strings.TrimPrefix(sessionKey, "dingtalk:")
	parts := strings.SplitN(stripped, ":", 3)

	if len(parts) < 2 {
		return nil, fmt.Errorf("dingtalk: invalid session key format: %q", sessionKey)
	}

	convType := parts[0]
	if convType != "g" && convType != "d" {
		return nil, fmt.Errorf("dingtalk: invalid conversation type %q in session key: %q", convType, sessionKey)
	}

	conversationId := parts[1]
	if conversationId == "" {
		return nil, fmt.Errorf("dingtalk: empty conversationId in session key: %q", sessionKey)
	}

	var senderStaffId string
	if len(parts) > 2 {
		senderStaffId = parts[2]
	}

	return replyContext{

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Print the offending key from the error and compare against 'dingtalk:{g|d}:{conversationId}[:{senderStaffId}]'.
  2. Rebuild the key from a live incoming DingTalk message instead of hand-editing the stored value.
  3. If keys were stored before a format change, migrate them to the current 3-4 segment format.
  4. Ensure no tooling strips or splits on ':' when persisting the key (e.g. TOML/env escaping issues).

Example fix

// before
sessionKey := "dingtalk:g"
rc, err := platform.ReconstructReplyCtx(sessionKey) // error: invalid format
// after
sessionKey := "dingtalk:g:cidXXXX" // convType + conversationId
rc, err := platform.ReconstructReplyCtx(sessionKey)
Defensive patterns

Strategy: validation

Validate before calling

func validDingtalkKeyShape(key string) bool {
    if !strings.HasPrefix(key, "dingtalk:") {
        return false
    }
    rest := strings.TrimPrefix(key, "dingtalk:")
    parts := strings.SplitN(rest, ":", 3)
    return len(parts) >= 2 && parts[0] != "" && parts[1] != ""
}
// call only if validDingtalkKeyShape(key) is true

Type guard

func hasMinSegments(key string) bool {
    return len(strings.SplitN(strings.TrimPrefix(key, "dingtalk:"), ":", 3)) >= 2
}

Try / catch

ctx, err := platform.ReconstructReplyCtx(sessionKey)
if err != nil {
    if strings.Contains(err.Error(), "invalid session key format") {
        slog.Error("malformed dingtalk key; refetch from sessions list", "key", sessionKey)
        return errKeyMalformed
    }
    return err
}

Prevention

When it happens

Trigger: Passing 'dingtalk:' or 'dingtalk:g' (only one segment) to ReconstructReplyCtx; a key truncated by storage/export tooling; a hand-edited key missing the conversation id.

Common situations: Databases or config files where colons were mangled by escaping/interpolation; copying a partial key from logs; keys built against an older format before the convType segment was introduced.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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