siyuan-note/siyuan · error

failed to read directory

Error message

failed to read directory: %w

What it means

os.ReadDir failed for the resolved path in siyuan.storage.list. The OS error is wrapped and the Promise is rejected with 'failed to read directory: <cause>'. Common causes are the path not existing or not being a directory (ENOENT, ENOTDIR) or lacking read permission.

Solutions

  1. Create the directory first (e.g. write a file with siyuan.storage.put) or treat ENOENT as an empty result
  2. Ensure the path is a directory, not a file
  3. Check the wrapped OS error to distinguish not-found from permission problems
  4. Wrap the call in try/catch and fall back to an empty list for optional directories

Example fix

// before
const entries = await siyuan.storage.list(dir);

// after
let entries = [];
try {
  entries = await siyuan.storage.list(dir);
} catch (e) {
  if (!String(e).includes("no such file")) throw e;
}
Defensive patterns

Strategy: fallback

Try / catch

let entries = [];
try {
  entries = await siyuan.storage.list(dir);
} catch (e) {
  if (String(e).includes("no such file")) {
    entries = []; // treat missing dir as empty
  } else throw e;
}

Prevention

When it happens

Trigger: Calling siyuan.storage.list(path) where path was never created (e.g. before the first storage.put), points to a file instead of a directory, or the directory cannot be read due to permissions.

Common situations: Listing a subdirectory before any file was written into it; a typo in the path; assuming list works on file paths; directories deleted externally by sync or the user.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/bf7e1f0b6654bef1. Report an issue: GitHub.

Appendix: source

Thrown at kernel/plugin/api_storage.go:427

						err = fmt.Errorf("panic during siyuan.storage.list: %v", r)
					}
					p.worker.Run(func(rt *goja.Runtime) (_ any, _ error) {
						if lo.IsNil(err) {
							if resolveErr := resolve(result); resolveErr != nil {
								logging.LogErrorf("[plugin:%s] siyuan.storage.list resolve: %v", p.Name, resolveErr)
							}
						} else {
							if rejectErr := reject(rt.NewGoError(err)); rejectErr != nil {
								logging.LogErrorf("[plugin:%s] siyuan.storage.list reject: %v", p.Name, rejectErr)
							}
						}
						return
					}, nil)
				}()

				entries, readErr := os.ReadDir(abs)
				if readErr != nil {
					err = fmt.Errorf("failed to read directory: %w", readErr)
					return
				}

				results := make([]R, 0, len(entries))
				for _, entry := range entries {
					info, infoErr := entry.Info()
					if infoErr != nil {
						continue
					}
					results = append(results, R{
						"name":      entry.Name(),
						"isDir":     info.IsDir(),
						"isSymlink": util.IsSymlink(entry),
						"updated":   info.ModTime().Unix(),
					})
				}

				result = results

View on GitHub (pinned to 9f775e8a12)