{"record":{"id":"b3cba007e93060e5","repo":"chenhg5/cc-connect","slug":"tuitui-channel-id-is-required","errorCode":null,"errorMessage":"tuitui: channel id is required","messagePattern":"tuitui: channel id is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/tuitui/tuitui.go","lineNumber":203,"sourceCode":"\tp.stopping = true\n\tif p.cancel != nil {\n\t\tp.cancel()\n\t}\n\treturn nil\n}\n\nfunc (p *Platform) Reply(ctx context.Context, replyCtx any, content string) error {\n\treturn p.sendText(ctx, replyCtx, content)\n}\n\nfunc (p *Platform) Send(ctx context.Context, replyCtx any, content string) error {\n\treturn p.sendText(ctx, replyCtx, content)\n}\n\nfunc (p *Platform) SendChannelPost(ctx context.Context, channelID, markdown, parentID string) error {\n\tchannelID = strings.TrimSpace(channelID)\n\tif channelID == \"\" {\n\t\treturn fmt.Errorf(\"tuitui: channel id is required\")\n\t}\n\tif strings.TrimSpace(markdown) == \"\" {\n\t\treturn fmt.Errorf(\"tuitui: markdown is required\")\n\t}\n\n\tchatID := channelID\n\tif guessChatType(channelID) == chatTypeChannel {\n\t\tif parentID = strings.TrimSpace(parentID); parentID != \"\" {\n\t\t\ttarget := teamsParseChatID(channelID)\n\t\t\tchatID = teamsBuildChatID(target[\"team_id\"], target[\"channel_id\"], parentID)\n\t\t}\n\t} else {\n\t\tinfo, err := p.getChannelInfo(ctx, channelID)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tteamID := stringFromAny(info[\"team_id\"])\n\t\tif teamID == \"\" {","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/tuitui/tuitui.go#L185-L221","documentation":"SendChannelPost requires a non-empty channel ID because the TuiTui API needs a destination chat/channel. The value is trimmed and validated first; an empty or whitespace-only ID aborts before any network call. This is a fail-fast input validation error.","triggerScenarios":"Calling SendChannelPost(ctx, \"\", markdown, parentID) or with a whitespace-only string (e.g. \"   \") as channelID.","commonSituations":"An upstream message record missing a channel identifier; a variable populated from an empty config field or unfound team/channel mapping passed straight through; splitting a session key that yielded no chat ID.","solutions":["Pass the actual TuiTui channel/chat ID (e.g. from the incoming message's reply context) as channelID.","Trim and check the ID at the call site before invoking SendChannelPost.","Fix the data source that produced an empty channel ID (config value, database field, or parsed key)."],"exampleFix":"// before\nerr := p.SendChannelPost(ctx, channel.ID, md, \"\") // channel.ID == \"\"\n// after\nif strings.TrimSpace(channel.ID) == \"\" {\n    return fmt.Errorf(\"no channel id for post\")\n}\nerr := p.SendChannelPost(ctx, channel.ID, md, \"\")","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(channelID) == \"\" {\n    return fmt.Errorf(\"cannot post: channel id is empty\")\n}","typeGuard":"func hasChannelID(id string) bool { return strings.TrimSpace(id) != \"\" }","tryCatchPattern":"if err := p.SendChannelPost(ctx, chID, md, parent); err != nil && strings.Contains(err.Error(), \"channel id is required\") {\n    log.Warn(\"skipping post: missing channel id\")\n}","preventionTips":["Validate identifiers at the boundary where they enter your code.","Never forward IDs from unverified sources (config, DB rows) without a non-empty check.","Log and skip rather than send when the destination is unknown."],"tags":["validation","argument","api"],"backgroundTag":"missing-required-argument","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}