AlistGo/alist · error
key with the same title already exists
Error message
key with the same title already exists
What it means
CreateSSHPublicKey enforces per-user title uniqueness: db.GetSSHPublicKeyByUserTitle(userId, title) succeeding means a key with that title already exists for this user, so creation is refused (the bool return is true, indicating the key was not created but no internal failure occurred). Titles are the user-facing handle for keys, so duplicates would be ambiguous.
Source
Thrown at internal/op/sshkey.go:14
package op
import (
"github.com/alist-org/alist/v3/internal/db"
"github.com/alist-org/alist/v3/internal/model"
"github.com/pkg/errors"
"golang.org/x/crypto/ssh"
"time"
)
func CreateSSHPublicKey(k *model.SSHPublicKey) (error, bool) {
_, err := db.GetSSHPublicKeyByUserTitle(k.UserId, k.Title)
if err == nil {
return errors.New("key with the same title already exists"), true
}
pubKey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(k.KeyStr))
if err != nil {
return err, false
}
k.Fingerprint = ssh.FingerprintSHA256(pubKey)
k.AddedTime = time.Now()
k.LastUsedTime = k.AddedTime
return db.CreateSSHPublicKey(k), true
}
func GetSSHPublicKeyByUserId(userId uint, pageIndex, pageSize int) (keys []model.SSHPublicKey, count int64, err error) {
return db.GetSSHPublicKeyByUserId(userId, pageIndex, pageSize)
}
func GetSSHPublicKeyByIdAndUserId(id uint, userId uint) (*model.SSHPublicKey, error) {
key, err := db.GetSSHPublicKeyById(id)
if err != nil {View on GitHub (pinned to 843d9dc814)
Solutions
- Delete or rename the existing key with that title first, then create the new one
- Use a distinct title (e.g. 'laptop-2026') for rotated keys
- Make setup scripts idempotent: check GetSSHPublicKeyByUserTitle before creating
Example fix
// before
err, created := op.CreateSSHPublicKey(&model.SSHPublicKey{UserId: uid, Title: "laptop", KeyStr: newKey})
// after: delete the stale entry with that title first
if _, err := db.GetSSHPublicKeyByUserTitle(uid, "laptop"); err == nil {
_ = db.DeleteSSHPublicKeyByTitle(uid, "laptop") // or update its KeyStr
}
err, created := op.CreateSSHPublicKey(&model.SSHPublicKey{UserId: uid, Title: "laptop", KeyStr: newKey}) Defensive patterns
Strategy: validation
Validate before calling
// Before creating a key
if _, err := db.GetSSHPublicKeyByUserTitle(k.UserId, k.Title); err == nil {
return errors.New("title in use; choose another or delete the old key")
} Try / catch
if err, created := op.CreateSSHPublicKey(k); err != nil {
if strings.Contains(err.Error(), "same title") {
// prompt user to pick a new title or replace the existing key
}
} Prevention
- Make key-provisioning scripts check title availability first
- Use dated/suffixed titles for rotated keys
- Expose existing titles in the UI's add-key form
When it happens
Trigger: Calling op.CreateSSHPublicKey with a title the same user already used for another key, regardless of the key material being different.
Common situations: Importing a rotated key under the old title (e.g. 'laptop') without deleting the previous entry; scripted key setup running twice; importing a keyset where titles collide.
Related errors
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/84947e0a45039708.
Report an issue: GitHub.