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

  1. Quote or convert the offending argument to a string (or array of strings) at the call site.
  2. Inspect the %T value in the panic message to identify the exact Go type being passed and adjust the caller.
  3. 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

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


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