{"record":{"id":"a126d39db0d34f20","repo":"chenhg5/cc-connect","slug":"start-thread-in-channel-s-w","errorCode":null,"errorMessage":"start thread in channel %s: %w","messagePattern":"start thread in channel (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/discord/discord.go","lineNumber":455,"sourceCode":"\t\tif ch.ParentID == \"\" {\n\t\t\treturn \"\", replyContext{}, core.ErrNotSupported\n\t\t}\n\t\tparent, err := ops.ResolveChannel(ch.ParentID)\n\t\tif err != nil {\n\t\t\treturn \"\", replyContext{}, fmt.Errorf(\"resolve parent channel %s: %w\", ch.ParentID, err)\n\t\t}\n\t\tparentChannelID = ch.ParentID\n\t\tparentType = parent.Type\n\t}\n\n\tthreadType, ok := standaloneThreadType(parentType)\n\tif !ok {\n\t\treturn \"\", replyContext{}, core.ErrNotSupported\n\t}\n\n\tthread, err := ops.StartStandaloneThread(parentChannelID, freshThreadName(title), threadType, 1440)\n\tif err != nil {\n\t\treturn \"\", replyContext{}, fmt.Errorf(\"start thread in channel %s: %w\", parentChannelID, err)\n\t}\n\tif err := ops.JoinThread(thread.ID); err != nil {\n\t\tslog.Debug(\"discord: join fresh thread failed\", \"thread\", thread.ID, \"error\", err)\n\t}\n\n\trc := replyContext{channelID: thread.ID, threadID: thread.ID}\n\treturn buildThreadSessionKey(thread.ID), rc, nil\n}\n\n// RegisterCommands registers bot commands with Discord for the slash command menu.\nfunc (p *Platform) RegisterCommands(commands []core.BotCommandInfo) error {\n\t// Wait for Ready event to ensure appID is populated\n\tselect {\n\tcase <-p.readyCh:\n\tcase <-time.After(15 * time.Second):\n\t\treturn fmt.Errorf(\"discord: timed out waiting for Ready event\")\n\t}\n","sourceCodeStart":437,"sourceCodeEnd":473,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/discord/discord.go#L437-L473","documentation":"resolveCronReplyTarget creates a fresh standalone thread in the resolved parent channel via ops.StartStandaloneThread. Failure is wrapped as \"start thread in channel <id>: <cause>\". This is the cron equivalent of error 1124 and inherits all the nil-session, permission, and channel-type constraints of ThreadStart.","triggerScenarios":"ops.StartStandaloneThread(parentChannelID, name, threadType, 1440) fails: bot lacks thread-creation permission in the parent channel, the parent is archived/locked or not a guild text/announcement/forum channel, or the sessionThreadOps guard rejects a nil session.","commonSituations":"Cron jobs targeting channels where the bot's role lacks \"Create Public Threads\", forum channels with restricted post creation, archived channels, or the platform being shut down when the cron fires.","solutions":["Read the wrapped cause; if it is \"session not initialized\", ensure Start() runs before the scheduler.","Grant the bot thread-creation permissions in the parent channel.","Move the cron target to an active, non-archived guild text channel.","Add a fallback that posts the cron output to the parent channel (no thread) when thread creation fails."],"exampleFix":"// before\nthread, err := ops.StartStandaloneThread(parentChannelID, freshThreadName(title), threadType, 1440)\nif err != nil {\n    return \"\", replyContext{}, fmt.Errorf(\"start thread in channel %s: %w\", parentChannelID, err)\n}\n// after\nthread, err := ops.StartStandaloneThread(parentChannelID, freshThreadName(title), threadType, 1440)\nif err != nil {\n    slog.Warn(\"discord: standalone thread creation failed for cron\", \"channel\", parentChannelID, \"error\", err)\n    rc := replyContext{channelID: parentChannelID}\n    return buildThreadSessionKey(parentChannelID), rc, nil\n}","handlingStrategy":"fallback","validationCode":"perm, err := session.State.UserChannelPermissions(botID, parentChannelID)\ncanThread := err == nil && perm&discordgo.PermissionCreatePublicThreads != 0","typeGuard":null,"tryCatchPattern":"thread, err := ops.StartStandaloneThread(parentChannelID, name, threadType, 1440)\nif err != nil {\n    slog.Warn(\"discord: cron thread creation failed; posting to channel\", \"channel\", parentChannelID, \"error\", err)\n    return buildThreadSessionKey(parentChannelID), replyContext{channelID: parentChannelID}, nil\n}","preventionTips":["Ensure bot roles include thread-creation rights in all cron target channels.","Start the platform before the scheduler can fire jobs.","Avoid archived/forum-restricted channels as cron targets."],"tags":["discord","cron","thread-creation","permissions"],"backgroundTag":"permission-denied","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"}