siyuan-note/siyuan · error

path required

Error message

path required

What it means

Thrown by the siyuan.client.fetch JS API exposed to plugins when the first argument is not a string. The fetch function routes HTTP requests to the kernel's own loopback server (http://127.0.0.1:{port}{path}), and the path must be a string starting with '/'. If goja.IsString returns false on call.Argument(0), the path is considered absent.

Source

Thrown at kernel/plugin/api_client.go:61

		}
	}()

	client := rt.NewObject()

	lo.Must0(client.Set("fetch", rt.ToValue(func(call goja.FunctionCall, rt *goja.Runtime) goja.Value {
		promise, resolve, reject := rt.NewPromise()

		var argErr error
		var path string
		method := "GET"
		headers := map[string]string{}
		var bodyString *string
		var bodyBytes *[]byte

		if goja.IsString(call.Argument(0)) {
			path = call.Argument(0).String()
		} else {
			argErr = fmt.Errorf("path required")
		}
		if argErr == nil && !strings.HasPrefix(path, "/") {
			argErr = fmt.Errorf("path must start with /")
		}
		if argErr == nil {
			if init := call.Argument(1); isJsValueNotNull(init) {
				if initObj := init.ToObject(rt); initObj != nil {
					if m := initObj.Get("method"); goja.IsString(m) {
						method = m.String()
					}

					if h := initObj.Get("headers"); isJsValueNotNull(h) {
						if exportErr := rt.ExportTo(h, &headers); exportErr != nil {
							argErr = fmt.Errorf("failed to export headers: %w", exportErr)
						}
					}

					if argErr == nil {

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Pass the API path as a plain string starting with '/', e.g., '/api/notebook/lsNotebooks'
  2. If using a URL object, convert to string and extract just the path portion
  3. Ensure the path argument is the first positional parameter

Example fix

// before
await siyuan.client.fetch({ url: '/api/notebook/lsNotebooks' });

// after
const resp = await siyuan.client.fetch('/api/notebook/lsNotebooks', {
  method: 'POST',
  body: JSON.stringify({})
});
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof path !== 'string' || !path.startsWith('/')) {
  throw new Error('First argument to siyuan.client.fetch must be a path string starting with /');
}
const resp = await siyuan.client.fetch(path, init);

Type guard

function isFetchPathArg(v) {
  return typeof v === 'string' && v.startsWith('/');
}

Try / catch

try {
  const resp = await siyuan.client.fetch(path, { method: 'POST', body: JSON.stringify(payload) });
} catch (e) {
  console.error('siyuan.client.fetch failed:', e.message);
}

Prevention

When it happens

Trigger: Calling siyuan.client.fetch() with no arguments, or with a non-string first argument such as a number, object, or URL instance. Example: siyuan.client.fetch(42) or siyuan.client.fetch({ url: '/api/...' }).

Common situations: Plugin developer passes an options object first (like browser fetch's init); uses a URL object instead of a string path; the path variable was never assigned; a refactor changed the call signature.

Related errors


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