chenhg5/cc-connect · error

no workspace binding for source channel %q

Error message

no workspace binding for source channel %q

What it means

In multi-workspace relay mode, resolveWorkspace returned an empty workspace and NO effective workspace binding exists for the source channel, so cc-connect cannot determine which workspace should handle the relayed message: 'no workspace binding for source channel %q'. Without a binding, relay routing cannot proceed. This is a configuration-gap error, not a runtime failure.

Source

Thrown at core/engine.go:15946

	if err != nil {
		return nil, nil, "", fmt.Errorf("invalid source session key: %w", err)
	}

	relaySessionKey := relayConversationKey(fromProject, platformName, chatID)
	if !e.multiWorkspace || e.workspaceBindings == nil {
		return e.agent, e.sessions, relaySessionKey, nil
	}

	channelKey := workspaceChannelKey(platformName, chatID)
	workspace, _, err := e.resolveWorkspace(e.platformForName(platformName), chatID)
	if err != nil {
		return nil, nil, "", fmt.Errorf("resolve relay workspace: %w", err)
	}
	if workspace == "" {
		if b, _, usable := e.lookupEffectiveWorkspaceBinding(channelKey); b != nil && !usable {
			return nil, nil, "", fmt.Errorf("workspace binding unavailable for source channel %q", channelKey)
		}
		return nil, nil, "", fmt.Errorf("no workspace binding for source channel %q", channelKey)
	}

	agent, sessions, err := e.getOrCreateWorkspaceAgent(workspace)
	if err != nil {
		return nil, nil, "", fmt.Errorf("get relay workspace agent: %w", err)
	}
	if ws := e.workspacePool.Get(workspace); ws != nil {
		ws.Touch()
	}
	return agent, sessions, relaySessionKey, nil
}

// HandleRelay processes a relay message synchronously: starts or resumes a
// dedicated relay session, sends the message to the agent, and blocks until
// the complete response is collected (or the relay context times out).
func (e *Engine) HandleRelay(ctx context.Context, fromProject, sourceSessionKey, message string) (string, error) {
	agent, sessions, relaySessionKey, err := e.relayContextForSourceSessionKey(fromProject, sourceSessionKey)
	if err != nil {

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Add a workspace binding for the printed channel key in config.toml
  2. Configure a default/fallback workspace so unbound channels still route
  3. Verify the channel key matches exactly what the platform emits (compare engine logs)
  4. If the channel should not be relayed, restrict relay commands to bound channels

Example fix

// before: no binding for telegram:12345678
// after (config.toml)
[[workspace_bindings]]
channel = "telegram:12345678"
path = "/home/user/projects/myapp"
Defensive patterns

Strategy: fallback

Validate before calling

// at startup: warn about channels used without bindings
if e.multiWorkspace {
    for _, ch := range recentRelayChannels() {
        if b, _, _ := e.lookupEffectiveWorkspaceBinding(ch); b == nil {
            slog.Warn("no workspace binding for channel", "channel", ch)
        }
    }
}

Try / catch

agent, sessions, key, err := e.relayContextForSourceSessionKey(project, srcKey)
if err != nil && strings.Contains(err.Error(), "no workspace binding") {
    // route to default workspace instead of failing
    agent, sessions, key, err = e.defaultWorkspaceContext()
}

Prevention

When it happens

Trigger: Relay is triggered from a channel that was never mapped to a workspace while multi-workspace mode is enabled — lookupEffectiveWorkspaceBinding finds no binding (b == nil) and resolveWorkspace yields "".

Common situations: New chat/channel used before bindings were configured; channel key changed (bot moved groups, platform ID changed); multi-workspace enabled globally but only some channels bound; typo in the channel key in config.

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


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