cayleygraph/cayley · error

expected js callback function

Error message

expected js callback function

What it means

runIteratorWithCallback expects the second argument of ForEach to be a callable JS function; goja.AssertFunction fails for anything else and the session returns this error. It is a plain Go error (returned, not panicked), so it surfaces as the result of ForEach/limit-bounded iteration.

Source

Thrown at query/gizmo/gizmo.go:193

	ctx := s.context()

	output := make([]interface{}, 0)
	err := iterator.Iterate(ctx, it).Paths(false).Limit(limit).EachValue(s.qs, func(v quad.Value) error {
		if o := s.quadValueToNative(v); o != nil {
			output = append(output, o)
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	return output, nil
}

func (s *Session) runIteratorWithCallback(it iterator.Shape, callback goja.Value, this goja.FunctionCall, limit int) error {
	fnc, ok := goja.AssertFunction(callback)
	if !ok {
		return fmt.Errorf("expected js callback function")
	}
	ctx, cancel := context.WithCancel(s.context())
	defer cancel()
	return iterator.Iterate(ctx, it).Paths(true).Limit(limit).TagEach(func(tags map[string]graph.Ref) error {
		tm, err := s.tagsToValueMap(tags)
		if err != nil || tm == nil {
			return err
		}
		_, err = fnc(this.This, s.vm.ToValue(tm))
		if err != nil {
			cancel()
		}
		return err
	})
}

func (s *Session) send(ctx context.Context, r *Result) bool {
	if s.limit > 0 && s.count >= s.limit {

View on GitHub (pinned to 81dcd7d73e)

Solutions

  1. Pass an actual function as the callback: .forEach(function(v){...}) or (v) => {...}.
  2. If you intended a limit, use the correct overload/order: ForEach(limit, callback).
  3. In Go embedding, ensure the goja.Value you pass is created from a JS function via vm.ToValue(func(...)).

Example fix

// before
p.forEach(10)
// after
p.forEach(function(v) { console.log(v); }, 10)
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof callback !== 'function') throw new Error('forEach requires a callback function');

Type guard

function isFunction(v) { return typeof v === 'function'; }

Try / catch

try { p.forEach(cb, 10); } catch (e) { if (String(e).includes('expected js callback function')) { /* pass a function */ } throw e; }

Prevention

When it happens

Trigger: Calling s.ForEach(limit) or ForEach with a non-function second argument — e.g. a string, object, undefined, or null — at query/gizmo/gizmo.go:193.

Common situations: JS scripts that forget the callback (forEach(10) intending a limit), or pass an arrow function stored as an object property that is undefined at call time.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of cayleygraph/cayley@81dcd7d73e (2026-09-06). Data as JSON: /api/errors/414df0460e3a4c0c. Report an issue: GitHub.