siyuan-note/siyuan · error

path belongs to encrypted notebook [%s]: %s

Error message

path belongs to encrypted notebook [%s]: %s

What it means

Thrown by the shared `absPath` helper when the resolved absolute path falls inside an encrypted notebook. `model.EncryptedRawPathBoxID` checks both the path itself and its longest existing parent (to defeat symlink bypass), returning the box ID if the path belongs to a notebook flagged as encrypted. The CLI deliberately blocks raw file access to encrypted notebook data so ciphertext is never read or written outside the decryption layer.

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 251596fc0d)

Solutions

  1. Decrypt or disable encryption on the notebook in the GUI before raw CLI access
  2. Use a higher-level command that goes through the decryption layer rather than `file` subcommands
  3. Exclude encrypted notebook IDs from batch file scripts

Example fix

// before
siyuan file read data/20200101-encsecret/doc.sy
// after
# Decrypt notebook in the GUI first, or use a model-level command:
# Settings - Security - disable encryption on that notebook
Defensive patterns

Strategy: validation

Validate before calling

// Before batch file ops, filter out encrypted notebooks:
for _, box := range openNotebooks {
    if model.IsEncryptedBox(box.ID) { continue }
    // only operate on box.ID paths
}

Prevention

When it happens

Trigger: Any `file` subcommand targeting a path under `data/<encryptedBoxID>/...`. The path may look normal but `EncryptedRawPathBoxID` resolves the box ID from the assets path and confirms `IsEncryptedBox(boxID)` is true.

Common situations: Forgetting a notebook was encrypted in settings; scripts iterating all notebooks without filtering encrypted ones; trying to grep or copy files out of an encrypted notebook for a backup.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/30b74e43d7ea011a. Report an issue: GitHub.