siyuan-note/siyuan · error

read dir [%s] failed: %w

Error message

read dir [%s] failed: %w

What it means

loadSiblingCustomOrder reads the parent directory on disk (under workspace data/<boxID>/<parentPath>) with os.ReadDir to enumerate sibling .sy files before applying the custom order. This error wraps the underlying OS error when that directory cannot be read — the file system entry is missing, unreadable, or is not a directory. The absolute path and original error are embedded in the message.

Source

Thrown at kernel/model/file.go:2745

			return fmt.Errorf("target ID [%s] must not be included in source IDs", targetID)
		}
		if _, ok := seen[sourceID]; ok {
			return fmt.Errorf("duplicate source ID [%s]", sourceID)
		}
		seen[sourceID] = struct{}{}
	}
	return nil
}

func isSortableDocument(tree *treenode.BlockTree) bool {
	return nil != tree && tree.ID == tree.RootID && "d" == tree.Type && !IsBoxDoc(tree.BoxID, tree.RootID)
}

func loadSiblingCustomOrder(boxID, parentPath string, fullSortIDs map[string]int) (ret []string, err error) {
	absParentPath := filepath.Join(util.DataDir, boxID, parentPath)
	files, err := os.ReadDir(absParentPath)
	if nil != err {
		return nil, fmt.Errorf("read dir [%s] failed: %w", absParentPath, err)
	}
	for _, file := range files {
		if file.IsDir() || !strings.HasSuffix(file.Name(), ".sy") {
			continue
		}
		id := strings.TrimSuffix(file.Name(), ".sy")
		if !ast.IsNodeIDPattern(id) || ("/" == parentPath && id == boxID) {
			continue
		}
		ret = append(ret, id)
	}
	sort.Slice(ret, func(i, j int) bool {
		leftSort, rightSort := fullSortIDs[ret[i]], fullSortIDs[ret[j]]
		if leftSort != rightSort {
			return leftSort < rightSort
		}
		leftTime, rightTime := util.TimeFromID(ret[i]), util.TimeFromID(ret[j])
		if leftTime != rightTime {

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Verify the directory printed in the error exists in the workspace data folder and is readable; restore it from sync/backup if missing
  2. Check notebook consistency (rebuild/reindex the notebook from the SiYuan UI) so paths match disk state
  3. Fix file system permissions on the workspace data directory
  4. Confirm the storage volume is mounted/available and the workspace path in the config is correct

Example fix

// before
absParentPath := filepath.Join(util.DataDir, boxID, parentPath)
files, err := os.ReadDir(absParentPath) // err ignored upstream -> wrapped error
// after
absParentPath := filepath.Join(util.DataDir, boxID, parentPath)
if _, statErr := os.Stat(absParentPath); statErr != nil {
    log.Warnf("parent path missing, skip reorder: %v", statErr)
    return
}
files, err := os.ReadDir(absParentPath)
Defensive patterns

Strategy: try-catch

Validate before calling

absParentPath := filepath.Join(util.DataDir, boxID, parentPath)
if info, err := os.Stat(absParentPath); err != nil || !info.IsDir() {
    return fmt.Errorf("parent path unavailable: %s", absParentPath)
}

Type guard

func dirExists(path string) bool {
    info, err := os.Stat(path)
    return err == nil && info.IsDir()
}

Try / catch

if _, err := os.ReadDir(absParentPath); err != nil {
    log.Warnf("cannot read %s: %v; skipping reorder", absParentPath, err)
    return
}

Prevention

When it happens

Trigger: Reordering docs whose parent folder no longer exists on disk (deleted externally or by an unsynced/corrupt sync state); the parent path points to a file instead of a directory; workspace data directory moved or on a detached/unmounted volume; permission problems on the data directory.

Common situations: Notebook data synced from another machine with missing folders; user manually deleted or moved folders inside the workspace while the kernel was running; external drive/network volume disconnected; path casing or workspace misconfiguration pointing at the wrong data root.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/8a4f0bd0658c39c4. Report an issue: GitHub.