{"record":{"id":"ee1bb2016c135def","repo":"semaphoreui/semaphore","slug":"becomekey-does-not-exist-in-keys-name","errorCode":null,"errorMessage":"BecomeKey does not exist in keys[].Name","messagePattern":"BecomeKey does not exist in keys\\[\\]\\.Name","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"services/project/restore.go","lineNumber":177,"sourceCode":"\n\tnewKey, err := b.store.CreateAccessKey(key)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\tb.keys = append(b.keys, newKey)\n\treturn nil\n}\n\nfunc (e BackupInventory) Verify(backup *BackupFormat) error {\n\tif err := verifyDuplicate[BackupInventory](e.Name, backup.Inventories); err != nil {\n\t\treturn err\n\t}\n\tif e.SSHKey != nil && getEntryByName[BackupAccessKey](e.SSHKey, backup.Keys) == nil {\n\t\treturn fmt.Errorf(\"SSHKey does not exist in keys[].Name\")\n\t}\n\tif e.BecomeKey != nil && getEntryByName[BackupAccessKey](e.BecomeKey, backup.Keys) == nil {\n\t\treturn fmt.Errorf(\"BecomeKey does not exist in keys[].Name\")\n\t}\n\treturn nil\n}\n\nfunc (e BackupInventory) Restore(b *BackupDB) error {\n\tvar SSHKeyID *int\n\tif e.SSHKey == nil {\n\t\tSSHKeyID = nil\n\t} else if k := findEntityByName[db.AccessKey](e.SSHKey, b.keys); k == nil {\n\t\tSSHKeyID = nil\n\t} else {\n\t\tSSHKeyID = &((*k).ID)\n\t}\n\tvar BecomeKeyID *int\n\tif e.BecomeKey == nil {\n\t\tBecomeKeyID = nil\n\t} else if k := findEntityByName[db.AccessKey](e.BecomeKey, b.keys); k == nil {\n\t\tBecomeKeyID = nil","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/semaphoreui/semaphore/blob/1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa/services/project/restore.go#L159-L195","documentation":"BackupInventory.Verify also validates the optional BecomeKey reference: the named access key must exist in backup.keys[]. If getEntryByName finds no matching BackupAccessKey, verification returns this error, ensuring privilege-escalation key references resolve before restore.","triggerScenarios":"Running backup Verify/restore preflight where inventory.become_key names an access key absent from keys[].name — key deleted/renamed at source, partial export, or manual edit.","commonSituations":"Sudo/become keys rotated and removed before backup; inventories referencing keys from a different project; backups filtered to exclude sensitive keys while inventories were kept.","solutions":["Add the missing access key to keys[] in the backup JSON.","Change become_key to reference an existing keys[].name entry.","Set become_key to null if privilege escalation is not required.","Re-export a full backup that includes both inventories and access keys."],"exampleFix":"// before\n\"become_key\": \"sudo-key\", \"keys\": [{\"name\": \"deploy-key\"}]\n// after\n\"become_key\": null  // or add sudo-key to keys[]","handlingStrategy":"validation","validationCode":"func inventoryBecomeKeyExists(b BackupFormat) error {\n    for _, inv := range b.Inventories {\n        if inv.BecomeKey != nil && getEntryByName[BackupAccessKey](*inv.BecomeKey, b.Keys) == nil {\n            return fmt.Errorf(\"inventory %q references missing become_key %q\", inv.Name, *inv.BecomeKey)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := backup.Verify(); err != nil {\n    if strings.Contains(err.Error(), \"BecomeKey does not exist\") {\n        // add the key or null the become_key reference, then retry\n    }\n    return err\n}","preventionTips":["Keep become/privilege keys in every export containing inventories.","Clean up become_key references when rotating keys.","Run backup Verify as a preflight gate before restore operations."],"tags":["backup-restore","validation","missing-reference"],"backgroundTag":"resource-not-found","analyzedSha":"1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa","analyzedAt":"2026-09-07T11:00:33.293Z","contentChangedAt":"2026-09-07T11:00:33.293Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}