chenhg5/cc-connect · error

googlechat: invalid session key %q

Error message

googlechat: invalid session key %q

What it means

ReconstructReplyCtx turns a persisted session key back into a replyContext so outbound sends (cron jobs, send-to-session, restart notices) can target the right space/thread. It throws this error when sessionKey does not start with the expected "googlechat:" prefix, meaning the key is not a googlechat session key and cannot be reconstructed.

Source

Thrown at platform/googlechat/googlechat.go:338

		if thread != "" {
			return sessionKeyPrefix + space + threadSep + thread
		}
		return sessionKeyPrefix + space
	case "user":
		return sessionKeyPrefix + space + ":" + user
	default:
		return sessionKeyPrefix + space
	}
}

// ReconstructReplyCtx rebuilds a reply context from a session key so proactive
// sends (cron, send-to-session, restart notices) can reach the right space and
// thread. Implements core.ReplyContextReconstructor.
func (p *Platform) ReconstructReplyCtx(sessionKey string) (any, error) {
	// googlechat:<space>  |  googlechat:<space>:t:<thread>  |  googlechat:<space>:<user>
	rest, ok := strings.CutPrefix(sessionKey, sessionKeyPrefix)
	if !ok {
		return nil, fmt.Errorf("googlechat: invalid session key %q", sessionKey)
	}
	if idx := strings.Index(rest, threadSep); idx != -1 {
		return replyContext{space: rest[:idx], thread: rest[idx+len(threadSep):]}, nil
	}
	// User-scoped keys append ":<user>" where user is "users/<id>"; strip a
	// trailing "users/..." segment to recover the bare space.
	if idx := strings.LastIndex(rest, ":users/"); idx != -1 {
		return replyContext{space: rest[:idx]}, nil
	}
	return replyContext{space: rest}, nil
}

// httpErrorBody reads up to 2048 bytes from resp.Body, closes it, and returns
// an error combining prefix, status code, and the response snippet.
func httpErrorBody(resp *http.Response, prefix string) error {
	b, _ := io.ReadAll(io.LimitReader(resp.Body, 2048))
	if err := resp.Body.Close(); err != nil {
		return fmt.Errorf("%s: status %d: %s (close body: %v)", prefix, resp.StatusCode, strings.TrimSpace(string(b)), err)

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Prefix the key with "googlechat:" (e.g. googlechat:spaces/AAA:t/THREAD or googlechat:spaces/AAA)
  2. Check where the session key is persisted — ensure cron/send-to-session jobs target googlechat sessions only
  3. Log/inspect the stored key to confirm it was written by the googlechat platform and not truncated

Example fix

// before
rc, err := p.ReconstructReplyCtx("spaces/AAAA")

// after
rc, err := p.ReconstructReplyCtx("googlechat:spaces/AAAA")
Defensive patterns

Strategy: validation

Validate before calling

func validGoogleChatKey(k string) bool { return strings.HasPrefix(k, "googlechat:") }
if !validGoogleChatKey(sessionKey) { return fmt.Errorf("not a googlechat session key: %q", sessionKey) }

Try / catch

rc, err := p.ReconstructReplyCtx(sessionKey)
if err != nil {
    slog.Warn("cannot reconstruct googlechat reply ctx; skipping send", "key", sessionKey, "err", err)
    return err
}

Prevention

When it happens

Trigger: Passing a session key produced by another platform (e.g. "telegram:12345"), a bare space name, an empty string, or a manually built key missing the "googlechat:" prefix to ReconstructReplyCtx.

Common situations: Cron or scheduled-send configs that hardcode a session key copied from the wrong platform; database rows created before googlechat support where the prefix scheme differs; code that constructs keys by hand instead of using the platform's session-key format.

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/169d6a75051bd1fb. Report an issue: GitHub.