{"record":{"id":"fecbffbedb2bf041","repo":"semaphoreui/semaphore","slug":"cannot-decrypt-access-key-perhaps-encryption-key","errorCode":null,"errorMessage":"cannot decrypt access key, perhaps encryption key was changed","messagePattern":"cannot decrypt access key, perhaps encryption key was changed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"services/server/access_key_serializer_local.go","lineNumber":179,"sourceCode":"\t\tsshKey := db.SshKey{\n\t\t\tPrivateKey: secret,\n\t\t}\n\n\t\tvar marshaled []byte\n\t\tmarshaled, err = json.Marshal(sshKey)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\n\t\tres = string(marshaled)\n\n\t\treturn\n\t}\n\n\tplaintext, decErr := decrypt(secret)\n\tif decErr != nil {\n\t\tif decErr.Error() == \"cipher: message authentication failed\" {\n\t\t\terr = fmt.Errorf(\"cannot decrypt access key, perhaps encryption key was changed\")\n\t\t} else {\n\t\t\terr = decErr\n\t\t}\n\t\treturn\n\t}\n\n\tres = string(plaintext)\n\treturn\n}\n","sourceCodeStart":161,"sourceCodeEnd":189,"githubUrl":"https://github.com/semaphoreui/semaphore/blob/1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa/services/server/access_key_serializer_local.go#L161-L189","documentation":"The stored secret ciphertext fails GCM/Authenticated-cipher verification ('cipher: message authentication failed'), which almost always means it was encrypted with a different encryption key than the one now configured. deserialize maps that specific cipher error to this human-readable message so operators know to check the encryption key (APSE encryption key / keyset).","triggerScenarios":"DeserializeSecret/DeserializeSecret2 decrypt() returns the GCM message-authentication-failure error — the server's configured encryption key differs from the key used when the secret was stored (key rotated/replaced, wrong APSE key id, restored DB without the matching key).","commonSituations":"Rotating or regenerating the server encryption key without rekeying access keys (RekeyAccessKeys not run); moving the DB between environments with different encryption keys; restoring a backup while the keyset file changed.","solutions":["Restore the original encryption key / keyset used when the secret was stored and retry.","If the old key is still available, configure it temporarily and run RekeyAccessKeys to re-encrypt all secrets with the current key.","If the key is lost, re-create the affected access keys with new secrets — the old ciphertext is unrecoverable."],"exampleFix":"// before: new key configured, old ciphertext undecryptable\nutil.Config.EncryptionKey = newKeySet\n// after: rekey with old key present, then switch\nutil.Config.EncryptionKey = oldKeySet\nerr := encryptionService.RekeyAccessKeys() // re-encrypts with current key","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if _, err := svc.DeserializeSecret(key); err != nil && strings.Contains(err.Error(), \"cannot decrypt access key\") { // encryption key changed\n    // restore original key, or run RekeyAccessKeys with the old key configured\n}","preventionTips":["Back up the encryption keyset securely alongside DB backups.","Never rotate the encryption key without running RekeyAccessKeys afterwards.","Keep one authoritative encryption key per environment; don't copy DBs across environments with different keys."],"tags":["go","encryption","decryption","secrets","key-rotation"],"backgroundTag":"decryption-failed","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"}