{"record":{"id":"f971c55821d197aa","repo":"chenhg5/cc-connect","slug":"no-workspace-binding-for-source-channel-q","errorCode":null,"errorMessage":"no workspace binding for source channel %q","messagePattern":"no workspace binding for source channel %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/engine.go","lineNumber":15946,"sourceCode":"\tif err != nil {\n\t\treturn nil, nil, \"\", fmt.Errorf(\"invalid source session key: %w\", err)\n\t}\n\n\trelaySessionKey := relayConversationKey(fromProject, platformName, chatID)\n\tif !e.multiWorkspace || e.workspaceBindings == nil {\n\t\treturn e.agent, e.sessions, relaySessionKey, nil\n\t}\n\n\tchannelKey := workspaceChannelKey(platformName, chatID)\n\tworkspace, _, err := e.resolveWorkspace(e.platformForName(platformName), chatID)\n\tif err != nil {\n\t\treturn nil, nil, \"\", fmt.Errorf(\"resolve relay workspace: %w\", err)\n\t}\n\tif workspace == \"\" {\n\t\tif b, _, usable := e.lookupEffectiveWorkspaceBinding(channelKey); b != nil && !usable {\n\t\t\treturn nil, nil, \"\", fmt.Errorf(\"workspace binding unavailable for source channel %q\", channelKey)\n\t\t}\n\t\treturn nil, nil, \"\", fmt.Errorf(\"no workspace binding for source channel %q\", channelKey)\n\t}\n\n\tagent, sessions, err := e.getOrCreateWorkspaceAgent(workspace)\n\tif err != nil {\n\t\treturn nil, nil, \"\", fmt.Errorf(\"get relay workspace agent: %w\", err)\n\t}\n\tif ws := e.workspacePool.Get(workspace); ws != nil {\n\t\tws.Touch()\n\t}\n\treturn agent, sessions, relaySessionKey, nil\n}\n\n// HandleRelay processes a relay message synchronously: starts or resumes a\n// dedicated relay session, sends the message to the agent, and blocks until\n// the complete response is collected (or the relay context times out).\nfunc (e *Engine) HandleRelay(ctx context.Context, fromProject, sourceSessionKey, message string) (string, error) {\n\tagent, sessions, relaySessionKey, err := e.relayContextForSourceSessionKey(fromProject, sourceSessionKey)\n\tif err != nil {","sourceCodeStart":15928,"sourceCodeEnd":15964,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/engine.go#L15928-L15964","documentation":"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.","triggerScenarios":"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 \"\".","commonSituations":"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.","solutions":["Add a workspace binding for the printed channel key in config.toml","Configure a default/fallback workspace so unbound channels still route","Verify the channel key matches exactly what the platform emits (compare engine logs)","If the channel should not be relayed, restrict relay commands to bound channels"],"exampleFix":"// before: no binding for telegram:12345678\n// after (config.toml)\n[[workspace_bindings]]\nchannel = \"telegram:12345678\"\npath = \"/home/user/projects/myapp\"","handlingStrategy":"fallback","validationCode":"// at startup: warn about channels used without bindings\nif e.multiWorkspace {\n    for _, ch := range recentRelayChannels() {\n        if b, _, _ := e.lookupEffectiveWorkspaceBinding(ch); b == nil {\n            slog.Warn(\"no workspace binding for channel\", \"channel\", ch)\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"agent, sessions, key, err := e.relayContextForSourceSessionKey(project, srcKey)\nif err != nil && strings.Contains(err.Error(), \"no workspace binding\") {\n    // route to default workspace instead of failing\n    agent, sessions, key, err = e.defaultWorkspaceContext()\n}","preventionTips":["Configure a default workspace fallback for unbound channels","Bind every channel you intend to relay from before enabling multi-workspace","Audit bindings when bots move chats or platform IDs change","Compare channel keys in config against engine-emitted keys (logs)"],"tags":["workspace","binding","relay","configuration"],"backgroundTag":"missing-required-config","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}