siyuan-note/siyuan · error

failed to make directory

Error message

failed to make directory: %w

What it means

os.MkdirAll failed when siyuan.storage.put tried to create the parent directories of the target file inside the plugin's storage directory (mode 0755). The wrapped OS error (%w) explains the cause — most often a permission problem, an existing non-directory file at a path component, or an invalid/over-long path.

Solutions

  1. Read the wrapped OS error in the rejection to identify the failing component
  2. Check that no file exists at any parent segment of the target path; remove or rename it (via siyuan.storage.remove or the filesystem)
  3. Verify the workspace directory and plugin storage dir are writable by the kernel process
  4. Shorten the path if it may exceed filesystem name/length limits

Example fix

// before
await siyuan.storage.put("data/config/app.json", s); // "data/config" exists as a FILE
// after
await siyuan.storage.remove("data/config").catch(() => {}); // clear conflicting file
await siyuan.storage.put("data/config/app.json", s);
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure no parent segment is used as both file and directory
if (usedAsFile.has(parentDir)) throw new Error(`"${parentDir}" is already a file`);

Type guard

null

Try / catch

try { await siyuan.storage.put(path, content); } catch (e) { if (String(e.message).includes("failed to make directory")) console.error("mkdir failed:", e.message); throw e; }

Prevention

When it happens

Trigger: A parent path component exists as a regular file (e.g. "data" is a file, so "data/x.json" cannot be created); the storage directory or a parent is read-only on disk; the workspace volume is full or the path exceeds NAME_MAX/MAX_PATH limits.

Common situations: Plugins writing to nested paths like "cache/http/resp.json" where a previous version stored a file at "cache"; running SiYuan from a location without write permissions; sync tools replacing directories with files.

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


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

Appendix: source

Thrown at kernel/plugin/api_storage.go:278

						err = fmt.Errorf("panic during siyuan.storage.put: %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.put resolve: %v", p.Name, resolveErr)
							}
						} else {
							if rejectErr := reject(rt.NewGoError(err)); rejectErr != nil {
								logging.LogErrorf("[plugin:%s] siyuan.storage.put reject: %v", p.Name, rejectErr)
							}
						}
						return
					}, nil)
				}()

				if mkdirErr := os.MkdirAll(filepath.Dir(abs), 0755); mkdirErr != nil {
					err = fmt.Errorf("failed to make directory: %w", mkdirErr)
					return
				}
				if writeErr := filelock.WriteFile(abs, []byte(content)); writeErr != nil {
					err = fmt.Errorf("failed to write file: %w", writeErr)
					return
				}
				return
			}()

			return
		}, func(rt *goja.Runtime, result any, err error) {
			if !lo.IsNil(err) {
				if rejectErr := reject(rt.NewGoError(err)); rejectErr != nil {
					logging.LogErrorf("[plugin:%s] siyuan.storage.put reject: %v", p.Name, rejectErr)
				}
			}
		})
		if runErr != nil {

View on GitHub (pinned to 9f775e8a12)