chenhg5/cc-connect · error
relay: no binding for this chat. Use /bind <project> first
Error message
relay: no binding for this chat. Use /bind <project> first
What it means
RelayManager.Send in core/relay.go throws this when the chat the request originates from has no relay binding registered in rm.bindings. A binding is created only after a user runs /bind in that chat, mapping the chat to one or more project bots. Without it, the relay manager refuses to route cross-project messages for safety.
Source
Thrown at core/relay.go:219
Response string `json:"response"`
}
// Send delivers a message from one bot to another and returns the response.
func (rm *RelayManager) Send(ctx context.Context, req RelayRequest) (*RelayResponse, error) {
platform, chatID, err := parseSessionKeyParts(req.SessionKey)
if err != nil {
return nil, fmt.Errorf("relay: invalid session key: %w", err)
}
rm.mu.RLock()
binding := rm.bindings[chatID]
targetEngine := rm.engines[req.To]
sourceEngine := rm.engines[req.From]
visibility := rm.visibility
rm.mu.RUnlock()
if binding == nil {
return nil, fmt.Errorf("relay: no binding for this chat. Use /bind <project> first")
}
if _, ok := binding.Bots[req.To]; !ok {
var bound []string
for proj := range binding.Bots {
if proj != req.From {
bound = append(bound, proj)
}
}
return nil, fmt.Errorf("relay: project %q is not bound in this chat. Available targets: %s (use the exact name)", req.To, strings.Join(bound, ", "))
}
if targetEngine == nil {
return nil, fmt.Errorf("relay: target engine %q not found (is the project running?)", req.To)
}
fromName := req.From
if binding.Bots[req.From] != "" {
fromName = binding.Bots[req.From]
}View on GitHub (pinned to 4000b2338a)
Solutions
- Run /bind <project> in the chat that is issuing the relay request, then retry
- Verify the SessionKey's chatID (via parseSessionKeyParts: 'platform:chatID:userID' or 'relay:sourceProject:chatID') matches the chat where the binding exists
- Re-register the binding programmatically if driving RelayManager from code (populate rm.bindings[chatID])
- If the chat was migrated/recreated, re-run /bind since the old chatID no longer matches
Example fix
// before: relay sent from an unbound chat
rm.Send(ctx, core.RelayRequest{From: "proj-a", To: "proj-b", SessionKey: "feishu:oc_newchat:u1", Message: "hi"})
// after: run "/bind proj-b" in chat oc_newchat first, or use the bound chat's key
rm.Send(ctx, core.RelayRequest{From: "proj-a", To: "proj-b", SessionKey: "feishu:oc_boundchat:u1", Message: "hi"}) Defensive patterns
Strategy: validation
Validate before calling
func chatBound(rm *core.RelayManager, sessionKey string) bool {
_, chatID, err := core.ParseSessionKeyParts(sessionKey) // or replicate SplitN(":", 3)
if err != nil { return false }
rm.Lock(); defer rm.Unlock()
return rm.Bindings()[chatID] != nil
}
// only call Send when chatBound(...) is true; otherwise prompt the user to run /bind Type guard
if binding := rm.LookupBinding(chatID); binding == nil { return fmt.Errorf("chat %s not bound; run /bind first", chatID) } Try / catch
resp, err := rm.Send(ctx, req)
if err != nil {
if strings.Contains(err.Error(), "no binding for this chat") {
reply("This chat is not bound. Use /bind <project> first.")
return
}
return err
} Prevention
- Run /bind in every chat before issuing relay commands
- Keep the session key's chatID stable — re-run /bind after group migration or bot re-invite
- In code, always derive SessionKey from the incoming message context, never hand-build it
When it happens
Trigger: Calling rm.Send(ctx, RelayRequest{From, To, SessionKey, Message}) where parseSessionKeyParts(SessionKey) yields a chatID that is not a key in rm.bindings — i.e. /bind was never run in that chat, or the SessionKey's chatID differs from the chat where /bind was executed.
Common situations: Users send relay commands (/to <project> <msg>) in a group or DM before ever running /bind; the bot moved to a new chat (new chatID) after a group migration; the session key passed programmatically has a chatID that doesn't match the bound chat.
Understand the failure class
Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.
Related errors
- workspace binding unavailable for source channel %q
- no workspace binding for source channel %q
- relay: project %q is not bound in this chat. Available targe
- acp: agent option "cmd" or "command" is required (path or na
- acp: command %q not found in PATH: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/eeb7f3b5b4b7ab98.
Report an issue: GitHub.