{"record":{"id":"5e0a12a3715c2556","repo":"chenhg5/cc-connect","slug":"tuitui-chat-id-is-required","errorCode":null,"errorMessage":"tuitui: chat id is required","messagePattern":"tuitui: chat id is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/tuitui/history.go","lineNumber":34,"sourceCode":"\tLimit        int    `json:\"limit,omitempty\"`\n\tOrderAsc     *bool  `json:\"order_asc,omitempty\"`\n}\n\ntype HistoryResult struct {\n\tErrCode     int              `json:\"errcode\"`\n\tErrMsg      string           `json:\"errmsg,omitempty\"`\n\tCursor      string           `json:\"cursor,omitempty\"`\n\tHasMore     bool             `json:\"has_more,omitempty\"`\n\tCurrentTime any              `json:\"current_time,omitempty\"`\n\tSubject     string           `json:\"subject,omitempty\"`\n\tMessages    []map[string]any `json:\"msgs,omitempty\"`\n\tThreads     []string         `json:\"threads,omitempty\"`\n}\n\nfunc (p *Platform) FetchHistory(ctx context.Context, chatID, chatType string, opts HistoryOptions) (*HistoryResult, error) {\n\tchatID = strings.TrimSpace(chatID)\n\tif chatID == \"\" {\n\t\treturn nil, fmt.Errorf(\"tuitui: chat id is required\")\n\t}\n\tif chatType == \"\" {\n\t\tchatType = guessChatType(chatID)\n\t}\n\tswitch chatType {\n\tcase chatTypeDirect, chatTypeGroup:\n\t\treturn p.fetchDirectOrGroupHistory(ctx, chatID, chatType, opts)\n\tcase chatTypeChannel:\n\t\treturn p.fetchChannelHistory(ctx, chatID, opts)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"tuitui: invalid chat type %q\", chatType)\n\t}\n}\n\nfunc (p *Platform) fetchDirectOrGroupHistory(ctx context.Context, chatID, chatType string, opts HistoryOptions) (*HistoryResult, error) {\n\tpayload := map[string]any{\"cursor\": \"0\"}\n\tif chatType == chatTypeDirect {\n\t\tpayload[\"user\"] = chatID","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/tuitui/history.go#L16-L52","documentation":"TuiTui's FetchHistory was called with an empty chatID. The platform cannot construct any history API request without knowing which chat to fetch, so it rejects the call upfront. This is a caller-contract violation, not a network failure.","triggerScenarios":"Calling FetchHistory(ctx, \"\", chatType, opts) directly, or routing a message whose chat ID was not extracted (e.g. webhook payload missing the chat identifier, or chatID that trims to whitespace).","commonSituations":"Integration code passing an uninitialized variable as chat ID; a message from an unsupported event type lacking a chat identifier forwarded to FetchHistory; test harness forgetting to set the chat ID field.","solutions":["Ensure the caller extracts chatID from the incoming message/event before calling FetchHistory.","Guard the call site: skip history fetch when chatID is empty.","Trim user-supplied IDs and validate non-empty before passing.","If the ID comes from config or a DB lookup, check that the lookup succeeded."],"exampleFix":"// before\nresult, err := p.FetchHistory(ctx, chatID, \"group\", opts)\n// after\nif strings.TrimSpace(chatID) == \"\" {\n    return nil, fmt.Errorf(\"cannot fetch history: chatID is empty\")\n}\nresult, err := p.FetchHistory(ctx, chatID, \"group\", opts)","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(chatID) == \"\" {\n    return fmt.Errorf(\"skip: chatID empty\")\n}","typeGuard":"func hasChatID(m core.Message) bool { return strings.TrimSpace(m.ChatID) != \"\" }","tryCatchPattern":"res, err := p.FetchHistory(ctx, chatID, chatType, opts)\nif err != nil && strings.Contains(err.Error(), \"chat id is required\") {\n    slog.Warn(\"no chat id available; skipping history fetch\")\n    return\n}","preventionTips":["Always extract chat ID from the event payload before history calls","Trim and validate IDs at the boundary of your integration layer","Add unit tests covering empty-ID paths","Fail fast with your own descriptive error when the upstream event lacks an ID"],"tags":["tuitui","validation","history"],"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"}