siyuan-note/siyuan · error

promise rejected: %v

Error message

promise rejected: %v

What it means

The handler returned a Promise and invokeFunction attached onFulfilled/onRejected callbacks via .then; the rejection callback fired, so the plugin's async operation rejected. %v is call.Argument(0).Export() — the rejection reason (an Error, string, or value).

Source

Thrown at kernel/plugin/sandbox.go:407

		}

		thenValue := resultObj.Get("then")
		then, ok := goja.AssertFunction(thenValue)
		if !ok {
			callback(rt, &CallResult{Error: fmt.Errorf("'promise.then property is not a function")})
			return
		}

		then(resultObj, rt.ToValue(func(call goja.FunctionCall, rt *goja.Runtime) {
			// ⚠️ call.Arguments always is an empty array.
			promise, ok := result.(*goja.Promise)
			if ok {
				callback(rt, &CallResult{Value: promise.Result()})
			} else {
				callback(rt, &CallResult{Value: resultJs})
			}
		}), rt.ToValue(func(call goja.FunctionCall, rt *goja.Runtime) {
			callback(rt, &CallResult{Error: fmt.Errorf("promise rejected: %v", call.Argument(0).Export())})
		}))
	} else {
		callback(rt, &CallResult{Value: resultJs})
	}
}

// isJsPromise checks if a goja.Value is a JavaScript Promise.
func isJsPromise(jsValue goja.Value) bool {
	if jsValue == nil {
		return false
	}

	goValue := jsValue.Export()
	return isGoPromise(goValue)
}

// isGoPromise checks if a Go value is a *goja.Promise.
func isGoPromise(goValue any) bool {

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Inspect the rejection reason in the error message (the %v) to find the root cause.
  2. Add try/catch inside the async handler and return a structured error or a safe default instead of rejecting.
  3. Validate inputs before performing the async operation that rejects.

Example fix

// before
handler = async (req) => { return await fetch(req.url) } // rejects on network error
// after
handler = async (req) => {
  try { return await fetch(req.url) }
  catch (e) { return { error: e.message } } // resolves instead of rejecting
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate inputs that commonly cause rejection before the async op.
function validateRequest(req: { url?: string }): void {
  if (!req.url) throw new Error('missing url')
  try { new URL(req.url) } catch { throw new Error('invalid url') }
}

Try / catch

// Resolve-with-structured-error instead of letting the Promise reject.
handler = async (req) => {
  try { return await doAsync(req) }
  catch (e) { return { ok: false, error: String(e) } }
}

Prevention

When it happens

Trigger: An async plugin handler calls reject, throws inside an async function, or awaits a rejected Promise. Surfaced through the registered server/event async hook during request processing.

Common situations: Plugin's fetch to an external service fails (network/404); plugin throws inside async handler due to bad input; uncaught rejection in a chained .then inside the handler.

Related errors


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