{"record":{"id":"30b74e43d7ea011a","repo":"siyuan-note/siyuan","slug":"path-belongs-to-encrypted-notebook-s-s","errorCode":null,"errorMessage":"path belongs to encrypted notebook [%s]: %s","messagePattern":"path belongs to encrypted notebook \\[(.+?)\\]: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/cli/cmd/file.go","lineNumber":47,"sourceCode":"\t\"github.com/siyuan-note/siyuan/kernel/model\"\n\t\"github.com/siyuan-note/siyuan/kernel/util\"\n\n\t\"github.com/spf13/cobra\"\n)\n\nvar fileCmd = &cobra.Command{\n\tUse:   \"file\",\n\tShort: \"Workspace file operations\",\n}\n\nfunc absPath(rel string) (string, error) {\n\trel = filepath.Clean(strings.ReplaceAll(rel, \"/\", string(os.PathSeparator)))\n\tabs := filepath.Join(util.WorkspaceDir, rel)\n\tif !gulu.File.IsSubPath(util.WorkspaceDir, abs) {\n\t\treturn \"\", fmt.Errorf(\"path escapes workspace: %s\", rel)\n\t}\n\tif boxID := model.EncryptedRawPathBoxID(abs); boxID != \"\" {\n\t\treturn \"\", fmt.Errorf(\"path belongs to encrypted notebook [%s]: %s\", boxID, rel)\n\t}\n\treturn abs, nil\n}\n\nvar fileListCmd = &cobra.Command{\n\tUse:   \"list <path>\",\n\tShort: \"List directory contents\",\n\tArgs:  cobra.MinimumNArgs(1),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tdir, err := absPath(args[0])\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tentries, err := os.ReadDir(dir)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/cli/cmd/file.go#L29-L65","documentation":"absPath additionally refuses paths that belong to an encrypted notebook. model.EncryptedRawPathBoxID checks whether the resolved absolute path lies inside a notebook that stores raw encrypted data; touching such paths via generic file commands would bypass the notebook's encryption envelope, so the helper returns this error identifying the box ID.","triggerScenarios":"Running a CLI file command (list/read/write) with a path that resolves inside an encrypted notebook's directory under data/<boxID>/ of a workspace with encrypted notebooks configured.","commonSituations":"Bulk scripts that walk all notebooks and hit the encrypted one; users unaware a notebook was created with encryption enabled; tools that enumerate data/ directly instead of using document-level APIs.","solutions":["Operate on encrypted notebooks only through document-level APIs/commands (export, editor) rather than raw file commands.","Check which notebooks are encrypted and exclude their paths from file scripts.","If the notebook should not be encrypted, create/keep the data in a regular notebook and migrate documents via supported export/import.","Resolve the box ID from the error message to identify which notebook is encrypted."],"exampleFix":"// before\nsiyuan file list notebooks/20240101120000-enc123/doc.sy\n// error: path belongs to encrypted notebook [20240101120000-enc123]: ...\n\n// after\nsiyuan export sy --id 20240501120000-xyz9876 --output doc.sy.zip","handlingStrategy":"try-catch","validationCode":"// Skip encrypted notebooks before touching their paths\nfor _, box := range boxes {\n    if box.Encrypted {\n        continue\n    }\n    // queue file operations for box.ID only\n}","typeGuard":null,"tryCatchPattern":"abs, err := absPath(rel)\nif err != nil {\n    if strings.Contains(err.Error(), \"path belongs to encrypted notebook\") {\n        // route through document-level export/API instead of raw file access\n        return ErrEncryptedNotebookPath\n    }\n    return err\n}","preventionTips":["Track which notebooks are encrypted and exclude them from raw file scripts","Use document-level commands (export sy/md-zip) for encrypted content","Parse the box ID from the error to identify the encrypted notebook","Do not try to bypass the guard by re-encrypting or editing raw files directly"],"tags":["security","encryption","cli","notebook"],"backgroundTag":"permission-denied","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"}