cayleygraph/cayley · error
expected string, got: %T
Error message
expected string, got: %T
What it means
toStrings in query/gizmo/environ.go converts variadic gizmo arguments into []string and panics when it encounters a value whose type is not a string, []string, []interface{}, or another recursively convertible form. Gizmo is a JavaScript-ish query API over a quad store, so via/tag arguments must be string-like; anything else (numbers, objects, booleans) is considered a programming error and is raised as a panic, not a returned error.
Source
Thrown at query/gizmo/environ.go:364
}
func toStrings(objs []interface{}) []string {
if len(objs) == 0 {
return nil
}
var out = make([]string, 0, len(objs))
for _, o := range objs {
switch v := o.(type) {
case string:
out = append(out, v)
case quad.Value:
out = append(out, quad.StringOf(v))
case []string:
out = append(out, v...)
case []interface{}:
out = append(out, toStrings(v)...)
default:
panic(fmt.Errorf("expected string, got: %T", o))
}
}
return out
}
func toVia(via []interface{}) []interface{} {
if len(via) == 0 {
return nil
} else if len(via) == 1 {
if via[0] == nil {
return nil
} else if v, ok := via[0].([]interface{}); ok {
return toVia(v)
} else if v, ok := via[0].([]string); ok {
arr := make([]interface{}, 0, len(v))
for _, s := range v {
arr = append(arr, s)
}View on GitHub (pinned to 81dcd7d73e)
Solutions
- Quote or convert the offending argument to a string (or array of strings) at the call site.
- Inspect the %T value in the panic message to identify the exact Go type being passed and adjust the caller.
- If the value is intentionally a value (not a predicate), wrap it in a path (e.g. g.V(value).out(...)) instead of passing it as a via/tag list.
Example fix
// before p.Both([1, 2, 3]) // after p.Both(["knows", "likes"])
Defensive patterns
Strategy: type-guard
Validate before calling
function isStringList(v) { return typeof v === 'string' || (Array.isArray(v) && v.every(x => typeof x === 'string')); }
if (!isStringList(via)) throw new Error('via must be a string or array of strings'); Type guard
function isStringArray(v) { return Array.isArray(v) && v.every(x => typeof x === 'string'); } Prevention
- Always quote predicate and tag names in gizmo scripts
- Lint query scripts for numeric/boolean arguments in via positions
- Convert user input with String() before passing to traversals
When it happens
Trigger: Calling a gizmo traversal (e.g. .both([1,2]), .tagValues via an array containing non-strings) or pathObject.Both/FollowRecursive paths that funnel through toViaData/toStrings with arguments that contain a non-string value such as a number, map, or goja object that toQuadValue handles elsewhere.
Common situations: JS query scripts that pass numeric tag lists or forget to quote predicate names (e.g. .both(42) or .both([true])), or embedding gizmo programmatically and passing Go values of unexpected types into exportArgs-produced argument lists.
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
- unsupported type: %T
- expected string, got: %T
- must specify a tag name when saving a path
- invalid argument type in filter()
- must execute a Step
AI-assisted analysis of cayleygraph/cayley@81dcd7d73e (2026-09-06).
Data as JSON: /api/errors/c9d8863bcd055248.
Report an issue: GitHub.