{"record":{"id":"e9e302a0eeebe6db","repo":"siyuan-note/siyuan","slug":"conf-language-316-box-id","errorCode":null,"errorMessage":"Conf.Language(316) + \" [box=\" + id + \"]\"","messagePattern":"Conf\\.Language\\(316\\) \\+ \" \\[box=\" \\+ id \\+ \"\\]\"","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"kernel/model/crypto.go","lineNumber":1757,"sourceCode":"\tif err != nil {\n\t\treturn err\n\t}\n\tnewVerifier, err := util.EncryptWithAAD(newKEK, kekVerifierMagic, []byte(\"siyuan:kek-verifier\"))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Phase 0: 遍历所有加密笔记本（含 conf 损坏但存在备份的），预计算新 WrappedDEK（内存操作）\n\t// 允许 entries 为空：用户可能已启用加密功能但尚未创建加密笔记本，此时仍需更新全局 verifier 和 backup。\n\tencBoxIDs, listErr := listAllEncryptedBoxIDs()\n\tif listErr != nil {\n\t\treturn fmt.Errorf(\"list encrypted notebooks failed: %w\", listErr)\n\t}\n\tvar entries []migrationBoxEntry\n\tfor _, id := range encBoxIDs {\n\t\tdek, boxCrypt, dErr := decryptBoxCrypt(id, oldKEK)\n\t\tif dErr != nil {\n\t\t\treturn errors.New(Conf.Language(316) + \" [box=\" + id + \"]\")\n\t\t}\n\t\tnewWrapped, nErr := util.EncryptWithAAD(newKEK, dek, wrappedDEKAAD(id))\n\t\tzeroAndClear(dek)\n\t\tif nErr != nil {\n\t\t\treturn nErr\n\t\t}\n\t\tentries = append(entries, migrationBoxEntry{\n\t\t\tBoxID:         id,\n\t\t\tNewSpec:       boxEncryptionSpec,\n\t\t\tNewWrappedDEK: newWrapped,\n\t\t\tNewWrapNonce:  mustEncryptionNonce(newWrapped),\n\t\t\tMetadata:      append([]byte(nil), boxCrypt.Metadata...),\n\t\t})\n\t}\n\n\t// Phase 1: 持久化 migration manifest（崩溃后 recovery 的依据）\n\tnewParamsJSON, _ := gulu.JSON.MarshalJSON(params)\n\tmig := &masterPasswordMigration{","sourceCodeStart":1739,"sourceCodeEnd":1775,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/crypto.go#L1739-L1775","documentation":"During master-password migration Phase 0, each encrypted notebook's BoxCrypt is decrypted with the old KEK via decryptBoxCrypt(). If decryption fails for a box, migration aborts with a localized message (Conf.Language(316): 'Decryption failed: incorrect key or corrupted data') plus the box ID. The migration refuses to proceed because it cannot re-wrap a DEK it cannot decrypt.","triggerScenarios":"ChangeMasterPassword iterating encBoxIDs calls decryptBoxCrypt(id, oldKEK); it fails when the notebook's WrappedDEK/backup was encrypted with a different KEK, the stored key material is corrupted, or the old password/KEK supplied does not match the one the box was wrapped under.","commonSituations":"User changed the master password previously and some notebook still holds key material wrapped under the older KEK; per-notebook conf or backup corrupted by an interrupted write; restoring a notebook from an old backup into a workspace with a newer master password.","solutions":["Retry the migration with the correct ORIGINAL master password (the one the box was wrapped under)","Identify the failing box from the [box=ID] suffix and check its .siyuan/conf.json and notebook crypt backup for corruption","If the notebook data is still accessible, decrypt/unlock it manually and re-encrypt under the current password before migrating","Restore the affected notebook's conf/backup from a known-good sync or backup snapshot, then retry"],"exampleFix":"// before: box wrapped under old KEK blocks migration\nChangeMasterPassword(currentPW, newPW) // -> Decryption failed: incorrect key or corrupted data [box=20240101120000-abcd123]\n// after: unlock/re-encrypt the box with the password it was created under, or restore its backup, then rerun ChangeMasterPassword","handlingStrategy":"validation","validationCode":"// Ensure every encrypted box decrypts under the current password before migrating\nfor _, id := range encBoxIDs {\n    if _, _, err := decryptBoxCrypt(id, oldKEK); err != nil {\n        return fmt.Errorf(\"box %s not decryptable with current password; resolve before migration\", id)\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := model.ChangeMasterPassword(old, new); err != nil {\n    if strings.Contains(err.Error(), \"Decryption failed\") && strings.Contains(err.Error(), \"[box=\") {\n        boxID := extractBetween(err.Error(), \"[box=\", \"]\")\n        // recover that box: correct password / restore its conf+backup from snapshot\n    }\n}","preventionTips":["Always perform password changes while logged in with the current master password verified (unlock an encrypted notebook first)","Avoid mixing notebooks restored from older-password backups into a workspace with a newer password without re-encrypting them","Take a workspace snapshot before any master-password migration","Let pending migrations complete before changing the password again"],"tags":["go","encryption","decryption-failed","key-management","migration"],"backgroundTag":"decryption-failed-incorrect-key","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}