cayleygraph/cayley · error
expected string, got: %T
Error message
expected string, got: %T
What it means
save's optional second argument is the output tag and must be a string; save narrows it with a Go type assertion and throws through the VM when it is anything else. The first argument is the predicate/path to save; the second names the key under which results appear.
Source
Thrown at query/gizmo/traversals.go:462
if rev {
np = np.HasReverse(via, qv...)
} else {
np = np.Has(via, qv...)
}
return p.newVal(np)
}
func (p *pathObject) save(call goja.FunctionCall, rev, opt bool) goja.Value {
args := exportArgs(call.Arguments)
if len(args) > 2 || len(args) == 0 {
return throwErr(p.s.vm, errArgCount{Got: len(args)})
}
var vtag interface{} = ""
if len(args) == 2 {
vtag = args[1]
}
tag, ok := vtag.(string)
if !ok {
return throwErr(p.s.vm, fmt.Errorf("expected string, got: %T", vtag))
}
via := args[0]
if vp, ok := via.(*pathObject); ok {
via = vp.path
if tag == "" {
return throwErr(p.s.vm, errors.New("must specify a tag name when saving a path"))
}
} else {
qv, err := toQuadValue(via)
via = qv
if err != nil {
return throwErr(p.s.vm, err)
}
if tag == "" {
if p.s.col == query.JSONLD {
switch qv := qv.(type) {
case quad.IRI:
tag = string(qv)View on GitHub (pinned to 81dcd7d73e)
Solutions
- Pass a plain string as the second argument: p.save("knows", "friendTag").
- Omit the second argument entirely to use the default tag.
- Coerce with String(x) in JS if the value may be non-string.
Example fix
// before
p.save("knows", 42)
// after
p.save("knows", "friend") Defensive patterns
Strategy: type-guard
Validate before calling
if (vtag !== undefined && typeof vtag !== 'string') throw new Error('save tag must be a string'); Type guard
function isStringOrUndefined(v) { return v === undefined || typeof v === 'string'; } Try / catch
try { p.save('knows', tag); } catch (e) { if (String(e).includes('expected string, got')) { tag = String(tag); } throw e; } Prevention
- Coerce tag variables with String() before calling save
- Omit the second argument to use the default tag
- Keep argument order: predicate first, tag second
When it happens
Trigger: Calling p.save("knows", 42), p.save(pred, {tag: ...}), or otherwise passing a non-string second argument that reaches query/gizmo/traversals.go:462.
Common situations: JS scripts passing a variable that is undefined/null or a number as the tag name, or accidentally reordering arguments so an object lands in the tag slot.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- expected string, got: %T
- must specify a tag name when saving a path
- invalid argument type in filter()
- must execute a Step
- unsupported type: %T
AI-assisted analysis of cayleygraph/cayley@81dcd7d73e (2026-09-06).
Data as JSON: /api/errors/9527679cf6a0df79.
Report an issue: GitHub.