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
- Pass an actual function as the callback: .forEach(function(v){...}) or (v) => {...}.
- If you intended a limit, use the correct overload/order: ForEach(limit, callback).
- 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
- Always pass a function argument to forEach
- Check argument order (limit vs callback) against the API docs
- In Go embedding, wrap functions with vm.ToValue(fn) before passing
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
- invalid argument type in filter()
- Datastore: invalid action
- token not valid
- gae quad: token not valid
- must specify a tag name when saving a path
AI-assisted analysis of cayleygraph/cayley@81dcd7d73e (2026-09-06).
Data as JSON: /api/errors/414df0460e3a4c0c.
Report an issue: GitHub.