siyuan-note/siyuan · error
path belongs to encrypted notebook
Error message
path belongs to encrypted notebook [%s]: %s
What it means
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.
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.
Example fix
// before siyuan file list notebooks/20240101120000-enc123/doc.sy // error: path belongs to encrypted notebook [20240101120000-enc123]: ... // after siyuan export sy --id 20240501120000-xyz9876 --output doc.sy.zip
Defensive patterns
Strategy: try-catch
Validate before calling
// Skip encrypted notebooks before touching their paths
for _, box := range boxes {
if box.Encrypted {
continue
}
// queue file operations for box.ID only
} Try / catch
abs, err := absPath(rel)
if err != nil {
if strings.Contains(err.Error(), "path belongs to encrypted notebook") {
// route through document-level export/API instead of raw file access
return ErrEncryptedNotebookPath
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- cannot swap blocks across encrypted notebook boundaries
- CLI does not support encrypted notebook
- Conf.Language(314)
- Access to encrypted notebook data is not supported via this…
- cannot replay block swap across encrypted notebook…
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/30b74e43d7ea011a.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/cli/cmd/file.go:47
"github.com/siyuan-note/siyuan/kernel/model"
"github.com/siyuan-note/siyuan/kernel/util"
"github.com/spf13/cobra"
)
var fileCmd = &cobra.Command{
Use: "file",
Short: "Workspace file operations",
}
func absPath(rel string) (string, error) {
rel = filepath.Clean(strings.ReplaceAll(rel, "/", string(os.PathSeparator)))
abs := filepath.Join(util.WorkspaceDir, rel)
if !gulu.File.IsSubPath(util.WorkspaceDir, abs) {
return "", fmt.Errorf("path escapes workspace: %s", rel)
}
if boxID := model.EncryptedRawPathBoxID(abs); boxID != "" {
return "", fmt.Errorf("path belongs to encrypted notebook [%s]: %s", boxID, rel)
}
return abs, nil
}
var fileListCmd = &cobra.Command{
Use: "list <path>",
Short: "List directory contents",
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
dir, err := absPath(args[0])
if err != nil {
return err
}
entries, err := os.ReadDir(dir)
if err != nil {
return err
}
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)View on GitHub (pinned to 9f775e8a12)