{"record":{"id":"cf95d142867c668f","repo":"Tencent/WeKnora","slug":"invalid-session-mode-s","errorCode":null,"errorMessage":"invalid session_mode: %s","messagePattern":"invalid session_mode: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/im/types.go","lineNumber":137,"sourceCode":"// on every save (create + update).\nfunc (ch *IMChannel) BeforeSave(tx *gorm.DB) error {\n\tif ch.SessionMode == \"\" {\n\t\tch.SessionMode = string(SessionModeUser)\n\t}\n\tif err := ch.validateSessionMode(); err != nil {\n\t\treturn err\n\t}\n\tch.BotIdentity = ch.computeBotIdentity()\n\treturn nil\n}\n\n// validateSessionMode checks that SessionMode holds a supported value.\nfunc (ch *IMChannel) validateSessionMode() error {\n\tswitch SessionMode(ch.SessionMode) {\n\tcase SessionModeUser, SessionModeThread:\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid session_mode: %s\", ch.SessionMode)\n\t}\n}\n\n// computeBotIdentity derives a unique bot identity string from the channel's\n// platform, mode, and credentials. Returns \"\" if no identity can be extracted.\nfunc (ch *IMChannel) computeBotIdentity() string {\n\tcreds := make(map[string]interface{})\n\tif err := json.Unmarshal([]byte(ch.Credentials), &creds); err != nil {\n\t\treturn \"\"\n\t}\n\n\tstr := func(key string) string {\n\t\tif v, ok := creds[key]; ok {\n\t\t\tswitch val := v.(type) {\n\t\t\tcase string:\n\t\t\t\treturn val\n\t\t\tcase float64:\n\t\t\t\treturn fmt.Sprintf(\"%.0f\", val)","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/im/types.go#L119-L155","documentation":"IMChannel.validateSessionMode enforces that the SessionMode column holds only SessionModeUser or SessionModeThread. BeforeCreate and BeforeSave hooks call it, so persisting a channel with any other value fails at the ORM layer with this message. It is a data-integrity guard against invalid enum values reaching the database.","triggerScenarios":"Saving (BeforeSave) or creating (BeforeCreate) an IMChannel whose SessionMode string is not exactly \"user\" or \"thread\" — e.g. an empty string, \"User\" with wrong casing, or a platform-specific value.","commonSituations":"Inserting channels directly via SQL or a migration script bypassing hooks earlier and then an update failing; constructing IMChannel structs in tests or seeders without setting SessionMode; renaming enum constants in a refactor without migrating existing rows.","solutions":["Set ch.SessionMode to im.SessionModeUser or im.SessionModeThread before calling Save/Create.","Query existing rows with invalid session_mode values and migrate them to a valid constant.","Validate user-supplied session_mode against the two allowed constants at the API boundary before constructing the struct."],"exampleFix":"// before\nch := &im.IMChannel{Platform: \"telegram\"}\ndb.Create(ch) // fails: empty SessionMode\n// after\nch := &im.IMChannel{Platform: \"telegram\", SessionMode: string(im.SessionModeThread)}\ndb.Create(ch)","handlingStrategy":"validation","validationCode":"func validSessionMode(s string) bool {\n    return s == string(im.SessionModeUser) || s == string(im.SessionModeThread)\n}\nif !validSessionMode(ch.SessionMode) {\n    ch.SessionMode = string(im.SessionModeThread) // or reject\n}","typeGuard":"func isSessionMode(s string) bool {\n    switch im.SessionMode(s) {\n    case im.SessionModeUser, im.SessionModeThread:\n        return true\n    }\n    return false\n}","tryCatchPattern":"if err := db.Create(ch).Error; err != nil {\n    if strings.Contains(err.Error(), \"invalid session_mode\") {\n        return fmt.Errorf(\"session_mode %q rejected; allowed: user, thread\", ch.SessionMode)\n    }\n    return err\n}","preventionTips":["Assign SessionMode only via the im.SessionMode* constants.","Backfill/migrate legacy rows so every row has a valid enum value.","Constrain the DB column with a CHECK or enum type as a second guard."],"tags":["validation","gorm-hook","enum"],"backgroundTag":"schema-validation-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}