beego/beego · error

one model must have one pk field only

Error message

one model must have one pk field only

What it means

A model was registered with more than one field marked `pk`. While collecting fields, beego assigns mi.Fields.Pk to the first pk field; a second field with fi.Pk set triggers 'one model must have one pk field only' and registration aborts (fatal via the 'field: ...' wrapper and os.Exit).

Source

Thrown at client/orm/internal/models/models_info_m.go:88

		fi, err = NewFieldInfo(mi, field, sf, mName)
		if err == errSkipField {
			err = nil
			continue
		} else if err != nil {
			break
		}
		// record current field index
		fi.FieldIndex = append(fi.FieldIndex, index...)
		fi.FieldIndex = append(fi.FieldIndex, i)
		fi.Mi = mi
		fi.InModel = true
		if !mi.Fields.Add(fi) {
			err = fmt.Errorf("duplicate column name: %s", fi.Column)
			break
		}
		if fi.Pk {
			if mi.Fields.Pk != nil {
				err = fmt.Errorf("one model must have one pk field only")
				break
			} else {
				mi.Fields.Pk = fi
			}
		}
	}

	if err != nil {
		fmt.Println(fmt.Errorf("field: %s.%s, %s", ind.Type(), sf.Name, err))
		os.Exit(2)
	}
}

// NewM2MModelInfo combine related model info to new model info.
// prepare for relation models query.
func NewM2MModelInfo(m1, m2 *ModelInfo) (mi *ModelInfo) {
	mi = new(ModelInfo)
	mi.Fields = NewFields()

View on GitHub (pinned to 939cfde380)

Solutions

  1. Keep exactly one pk per model, typically `Id int `orm:"pk;auto"``
  2. When embedding a base struct that already has the pk, do not declare another pk in the child
  3. For secondary unique keys use `unique` instead of `pk`
  4. For join tables, let beego auto-generate them (rel(m2m)) instead of hand-modeling composite keys

Example fix

// before
Id    int    `orm:"pk;auto"`
Email string `orm:"pk"`
// after
Id    int    `orm:"pk;auto"`
Email string `orm:"unique"`
Defensive patterns

Strategy: validation

Validate before calling

func countPk(t reflect.Type) int {
    n := 0
    for i := 0; i < t.NumField(); i++ {
        if strings.Contains(t.Field(i).Tag.Get("orm"), "pk") { n++ }
    }
    return n
}
// assert countPk == 1 for every registered model in a startup test

Prevention

When it happens

Trigger: Two fields with `orm:"pk"` in one struct; a struct embedding a base model that already declares a pk while the child declares another; `orm:"pk;auto"` on Id plus `orm:"pk"` on a natural key like Email.

Common situations: Embedding a shared BaseModel (with Id pk) and redeclaring a pk in the child; composite-key habits from other ORMs — beego does not support composite primary keys via multiple pk tags.

Related errors


AI-assisted analysis of beego/beego@939cfde380 (2026-08-15). Data as JSON: /api/errors/f652e2082c803aea. Report an issue: GitHub.