{"record":{"id":"0dc638c3c67ac24f","repo":"siyuan-note/siyuan","slug":"encrypted-notebook-s-has-no-valid-identity","errorCode":null,"errorMessage":"encrypted notebook [%s] has no valid identity","messagePattern":"encrypted notebook \\[(.+?)\\] has no valid identity","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/import.go","lineNumber":1077,"sourceCode":"\t\t}\n\n\t\tvar backup *conf.BoxEncryption\n\t\tif filelock.IsExist(backupPath) {\n\t\t\tbackup, err = readBoxEncryptionFile(backupPath)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid imported notebook identity [%s]: %w\", boxID, err)\n\t\t\t}\n\t\t}\n\n\t\tvar boxCrypt *conf.BoxEncryption\n\t\tif boxConf != nil && boxConf.Encrypted {\n\t\t\tif boxConf.BoxCrypt != nil && validateBoxEncryption(boxConf.BoxCrypt) == nil {\n\t\t\t\tboxCrypt = boxConf.BoxCrypt\n\t\t\t} else {\n\t\t\t\tboxCrypt = backup\n\t\t\t}\n\t\t\tif boxCrypt == nil {\n\t\t\t\treturn nil, fmt.Errorf(\"encrypted notebook [%s] has no valid identity\", boxID)\n\t\t\t}\n\t\t} else if boxConf != nil && backup != nil {\n\t\t\treturn nil, fmt.Errorf(\"notebook [%s] has conflicting normal and encrypted identities\", boxID)\n\t\t} else if backup != nil {\n\t\t\tboxCrypt = backup\n\t\t}\n\n\t\tpayloadFound, payloadErr := hasEncryptedNotebookPayloadAtPath(boxDir)\n\t\tif payloadErr != nil {\n\t\t\treturn nil, fmt.Errorf(\"inspect imported notebook [%s] failed: %w\", boxID, payloadErr)\n\t\t}\n\t\tif boxCrypt == nil && payloadFound {\n\t\t\treturn nil, fmt.Errorf(\"imported notebook [%s] contains encrypted payload without identity\", boxID)\n\t\t}\n\t\tif boxCrypt == nil {\n\t\t\tcontinue\n\t\t}\n","sourceCodeStart":1059,"sourceCodeEnd":1095,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/import.go#L1059-L1095","documentation":"Thrown by validateImportedNotebookIdentities when the conf.json marks the notebook as encrypted (Encrypted: true) but no valid encryption identity can be found. The kernel first tries BoxCrypt from conf.json (if it passes validateBoxEncryption), then falls back to the backup file. If both are nil or invalid, the notebook has no way to unwrap its DEK, making its content permanently inaccessible. The import is refused to avoid importing unrecoverable data.","triggerScenarios":"Calling validateImportedNotebookIdentities where boxConf.Encrypted is true, but both boxConf.BoxCrypt is nil-or-invalid AND the backup file is nil-or-absent. The check is at import.go:1070-1078.","commonSituations":"Exporting from a SiYuan version that stored encryption identity in a different location than the current version expects. Partial export that omitted the .siyuan/ directory or the backup file. Manual deletion of encryption files from the Data.zip. Conf.json edited to set Encrypted=true without providing BoxCrypt.","solutions":["Re-export the Data.zip ensuring the .siyuan/ directory with encryption identity files is included.","Verify the source SiYuan version matches the target version (encryption identity format must be compatible).","If the source notebook is truly encrypted but identity is lost, the data is unrecoverable — re-export from a backup that includes the identity.","If encryption was never intended, edit the conf.json in the Data.zip to set Encrypted to false before importing."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Check that encrypted notebooks in the archive have encryption identity\nfunc checkEncryptedNotebookIdentity(tmpDataPath, boxID string) error {\n    confPath := filepath.Join(tmpDataPath, boxID, \".siyuan\", \"conf.json\")\n    backupPath := filepath.Join(tmpDataPath, boxID, \".siyuan\", notebookCryptoBackupFilename)\n    if !filelock.IsExist(confPath) {\n        return nil\n    }\n    data, _ := filelock.ReadFile(confPath)\n    boxConf := conf.NewBoxConf()\n    if err := gulu.JSON.UnmarshalJSON(data, boxConf); err != nil {\n        return err\n    }\n    if !boxConf.Encrypted {\n        return nil\n    }\n    if boxConf.BoxCrypt != nil && validateBoxEncryption(boxConf.BoxCrypt) == nil {\n        return nil\n    }\n    if !filelock.IsExist(backupPath) {\n        return fmt.Errorf(\"encrypted notebook %s has no identity and no backup\", boxID)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"encryptedBoxIDs, err := validateImportedNotebookIdentities(tmpDataPath)\nif err != nil {\n    if strings.Contains(err.Error(), \"has no valid identity\") {\n        // Cannot recover — data would be inaccessible\n        return fmt.Errorf(\"encrypted notebook identity is missing; re-export with .siyuan/ directory\")\n    }\n}","preventionTips":["Always include the complete .siyuan/ directory when exporting encrypted notebooks.","Verify the archive contains both conf.json and the encryption backup file for encrypted notebooks.","Do not strip hidden directories from the Data.zip.","Re-export from the source SiYuan if identity files are missing."],"tags":["encryption","import","data-zip","identity","unrecoverable"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}