Tencent/WeKnora · error

invalid session_mode: %s

Error message

invalid session_mode: %s

What it means

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.

Source

Thrown at internal/im/types.go:137

// on every save (create + update).
func (ch *IMChannel) BeforeSave(tx *gorm.DB) error {
	if ch.SessionMode == "" {
		ch.SessionMode = string(SessionModeUser)
	}
	if err := ch.validateSessionMode(); err != nil {
		return err
	}
	ch.BotIdentity = ch.computeBotIdentity()
	return nil
}

// validateSessionMode checks that SessionMode holds a supported value.
func (ch *IMChannel) validateSessionMode() error {
	switch SessionMode(ch.SessionMode) {
	case SessionModeUser, SessionModeThread:
		return nil
	default:
		return fmt.Errorf("invalid session_mode: %s", ch.SessionMode)
	}
}

// computeBotIdentity derives a unique bot identity string from the channel's
// platform, mode, and credentials. Returns "" if no identity can be extracted.
func (ch *IMChannel) computeBotIdentity() string {
	creds := make(map[string]interface{})
	if err := json.Unmarshal([]byte(ch.Credentials), &creds); err != nil {
		return ""
	}

	str := func(key string) string {
		if v, ok := creds[key]; ok {
			switch val := v.(type) {
			case string:
				return val
			case float64:
				return fmt.Sprintf("%.0f", val)

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Set ch.SessionMode to im.SessionModeUser or im.SessionModeThread before calling Save/Create.
  2. Query existing rows with invalid session_mode values and migrate them to a valid constant.
  3. Validate user-supplied session_mode against the two allowed constants at the API boundary before constructing the struct.

Example fix

// before
ch := &im.IMChannel{Platform: "telegram"}
db.Create(ch) // fails: empty SessionMode
// after
ch := &im.IMChannel{Platform: "telegram", SessionMode: string(im.SessionModeThread)}
db.Create(ch)
Defensive patterns

Strategy: validation

Validate before calling

func validSessionMode(s string) bool {
    return s == string(im.SessionModeUser) || s == string(im.SessionModeThread)
}
if !validSessionMode(ch.SessionMode) {
    ch.SessionMode = string(im.SessionModeThread) // or reject
}

Type guard

func isSessionMode(s string) bool {
    switch im.SessionMode(s) {
    case im.SessionModeUser, im.SessionModeThread:
        return true
    }
    return false
}

Try / catch

if err := db.Create(ch).Error; err != nil {
    if strings.Contains(err.Error(), "invalid session_mode") {
        return fmt.Errorf("session_mode %q rejected; allowed: user, thread", ch.SessionMode)
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/cf95d142867c668f. Report an issue: GitHub.