{"record":{"id":"c9d8863bcd055248","repo":"cayleygraph/cayley","slug":"expected-string-got-t","errorCode":null,"errorMessage":"expected string, got: %T","messagePattern":"expected string, got: %T","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"query/gizmo/environ.go","lineNumber":364,"sourceCode":"}\n\nfunc toStrings(objs []interface{}) []string {\n\tif len(objs) == 0 {\n\t\treturn nil\n\t}\n\tvar out = make([]string, 0, len(objs))\n\tfor _, o := range objs {\n\t\tswitch v := o.(type) {\n\t\tcase string:\n\t\t\tout = append(out, v)\n\t\tcase quad.Value:\n\t\t\tout = append(out, quad.StringOf(v))\n\t\tcase []string:\n\t\t\tout = append(out, v...)\n\t\tcase []interface{}:\n\t\t\tout = append(out, toStrings(v)...)\n\t\tdefault:\n\t\t\tpanic(fmt.Errorf(\"expected string, got: %T\", o))\n\t\t}\n\t}\n\treturn out\n}\n\nfunc toVia(via []interface{}) []interface{} {\n\tif len(via) == 0 {\n\t\treturn nil\n\t} else if len(via) == 1 {\n\t\tif via[0] == nil {\n\t\t\treturn nil\n\t\t} else if v, ok := via[0].([]interface{}); ok {\n\t\t\treturn toVia(v)\n\t\t} else if v, ok := via[0].([]string); ok {\n\t\t\tarr := make([]interface{}, 0, len(v))\n\t\t\tfor _, s := range v {\n\t\t\t\tarr = append(arr, s)\n\t\t\t}","sourceCodeStart":346,"sourceCodeEnd":382,"githubUrl":"https://github.com/cayleygraph/cayley/blob/81dcd7d73e45136bc0d01802a8ba4685d8a533eb/query/gizmo/environ.go#L346-L382","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\np.Both([1, 2, 3])\n// after\np.Both([\"knows\", \"likes\"])","handlingStrategy":"type-guard","validationCode":"function isStringList(v) { return typeof v === 'string' || (Array.isArray(v) && v.every(x => typeof x === 'string')); }\nif (!isStringList(via)) throw new Error('via must be a string or array of strings');","typeGuard":"function isStringArray(v) { return Array.isArray(v) && v.every(x => typeof x === 'string'); }","tryCatchPattern":null,"preventionTips":["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"],"tags":["gizmo","query","type-mismatch","panic"],"backgroundTag":"type-mismatch","analyzedSha":"81dcd7d73e45136bc0d01802a8ba4685d8a533eb","analyzedAt":"2026-09-06T06:14:12.358Z","contentChangedAt":"2026-09-06T06:14:12.358Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}