siyuan-note/siyuan · error

path required

Error message

path required

What it means

siyuan.storage methods require the target path as a string first argument. When the argument is missing or is not a string, the promise rejects with 'path required'. The check is len(call.Arguments) >= 1 && goja.IsString(...), so undefined, null, and non-strings all fail identically.

Solutions

  1. Pass the relative path as a string first argument: storage.get('data.json')
  2. For set/remove, ensure the key/path argument is not accidentally omitted or shifted
  3. Coerce dynamic keys with String(key) after verifying they are defined
  4. Guard call sites: if (!path || typeof path !== 'string') return before calling

Example fix

// before
await siyuan.storage.set({ count: 1 })
// after
await siyuan.storage.set('state.json', JSON.stringify({ count: 1 }))
Defensive patterns

Strategy: validation

Validate before calling

if (typeof path !== 'string' || !path) throw new TypeError('storage path required')

Type guard

const hasPath = (v) => typeof v === 'string' && v.length > 0

Try / catch

try { await siyuan.storage.get(path) } catch (e) { if (e.message === 'path required') { /* argument missing or non-string */ } throw e }

Prevention

When it happens

Trigger: Calling storage.get(), storage.set(), storage.remove(), etc. with no argument, or with a non-string first argument such as an object, number, or null.

Common situations: Forgetting the path when only data was meant (e.g. set(value) instead of set(key, value)); a key variable that is undefined because an earlier lookup failed; numeric IDs passed without String() conversion.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at kernel/plugin/api_storage.go:59

		abs = filepath.Join(p.storageDir, filepath.Clean(relPath))
		if !(abs == p.storageDir || strings.HasPrefix(abs, p.storageDir+string(filepath.Separator))) {
			err = fmt.Errorf("siyuan.storage: path traversal not allowed")
		}
		return
	}

	watcher := rt.NewObject()

	// siyuan.storage.watcher.add(path) -> Promise<void>
	lo.Must0(watcher.Set("add", rt.ToValue(func(call goja.FunctionCall, rt *goja.Runtime) goja.Value {
		promise, resolve, reject := rt.NewPromise()

		var argErr error
		var path string
		if len(call.Arguments) >= 1 && goja.IsString(call.Argument(0)) {
			path = call.Argument(0).String()
		} else {
			argErr = fmt.Errorf("path required")
		}

		runErr := p.worker.Run(func(rt *goja.Runtime) (result any, err error) {
			if argErr != nil {
				err = argErr
				return
			}
			abs, resolveErr := resolvePath(path)
			if resolveErr != nil {
				err = resolveErr
				return
			}
			if addErr := p.addStorageWatch(abs); addErr != nil {
				err = fmt.Errorf("failed to add storage path to watcher: %v", addErr)
			}
			return
		}, func(rt *goja.Runtime, result any, err error) {
			if lo.IsNil(err) {

View on GitHub (pinned to 9f775e8a12)