{"record":{"id":"564a650b00862cc4","repo":"siyuan-note/siyuan","slug":"cli-does-not-support-encrypted-notebook-s","errorCode":null,"errorMessage":"CLI does not support encrypted notebook [%s]","messagePattern":"CLI does not support encrypted notebook \\[(.+?)\\]","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/cli/cmd/root.go","lineNumber":136,"sourceCode":"\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t},\n}\n\n// rejectEncryptedNotebookCLI 拒绝 CLI 对加密笔记本及其块的操作。\n// 加密笔记本只能通过应用内专用流程解锁和操作，避免 CLI 进程成为明文或密文文件的旁路入口。\nfunc rejectEncryptedNotebookCLI(cmd *cobra.Command, args []string) error {\n\tif cmd == serveCmd {\n\t\treturn nil\n\t}\n\tif (cmd == notebookRandomIconCmd && !cmd.Flags().Changed(\"id\")) || cmd == exportDataCmd {\n\t\tboxID, err := firstEncryptedNotebookID()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif boxID != \"\" {\n\t\t\treturn fmt.Errorf(\"CLI does not support encrypted notebook [%s]\", boxID)\n\t\t}\n\t}\n\n\tvar encryptedTarget string\n\tcheckID := func(id string) bool {\n\t\tif id == \"\" {\n\t\t\treturn false\n\t\t}\n\t\tif model.IsEncryptedBox(id) {\n\t\t\tencryptedTarget = id\n\t\t\treturn true\n\t\t}\n\t\tif bt := treenode.GetBlockTree(id); bt != nil && model.IsEncryptedBox(bt.BoxID) {\n\t\t\tencryptedTarget = bt.BoxID\n\t\t\treturn true\n\t\t}\n\t\treturn false\n\t}","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/cli/cmd/root.go#L118-L154","documentation":"Thrown by `rejectEncryptedNotebookCLI` when the command is `notebook random-icon` (without `--id`) or `export data`, AND at least one encrypted notebook exists in the workspace (`firstEncryptedNotebookID` returns a non-empty boxID). SiYuan encrypts notebook contents at rest; the CLI process is not an unlock path, so bulk operations over all notebooks are blocked to avoid leaking ciphertext handling or bypassing the in-app unlock flow. The error names the first encrypted box ID found.","triggerScenarios":"Running `siyuan notebook random-icon` (no `--id`) or `siyuan export data` while any notebook in the workspace is encrypted. The guard scans all notebooks via `model.ListNotebooks` and stops at the first encrypted one.","commonSituations":"Workspace has one or more password-protected notebooks; operator tries to bulk-export data or regenerate icons from the CLI without realizing encrypted notebooks exist; automating backups via `export data` against a mixed workspace.","solutions":["For `notebook random-icon`, target a specific non-encrypted notebook with `--id <boxID>` to skip the all-notebooks scan.","For `export data`, decrypt or remove the encrypted notebook(s) via the GUI app first, or use the GUI's own export flow.","If you must operate, ensure no encrypted notebooks are present in the workspace before running the CLI command."],"exampleFix":"// before\nsiyuan export data\n// after (target a specific notebook instead of all)\nsiyuan notebook random-icon --id 20240101000000nonencrypted","handlingStrategy":"validation","validationCode":"// Before `notebook random-icon` (no --id) or `export data`, check for encrypted notebooks.\nboxes, err := model.ListNotebooks()\nif err != nil { log.Fatal(err) }\nfor _, b := range boxes {\n    if model.IsEncryptedBox(b.ID) {\n        log.Fatalf(\"encrypted notebook %s present — decrypt via GUI or target a specific notebook with --id\", b.ID)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["For `notebook random-icon`, always pass a specific non-encrypted `--id`.","Avoid `export data` on workspaces containing encrypted notebooks; use the GUI flow.","Decrypt or remove encrypted notebooks before bulk CLI operations."],"tags":["cli","security","encryption","notebook","access-control"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}