cayleygraph/cayley · error

unexpected value type for

Error message

unexpected value type for %v: %T

What it means

When translating limit/skip constraints, iterateObject requires the single value to be a quad.Int; any other value type (string, float, bool) returns this error naming the key and the offending Go type. This enforces that pagination parameters are integers.

Solutions

  1. Convert the value to quad.Int before building the Has constraint (quad.Int(n)).
  2. Ensure the GraphQL layer coerces integer-typed fields and rejects strings at parse time.
  3. If you receive this from user input, validate that limit/skip are integers (no quotes) in the request.

Example fix

// before
Values: []interface{}{quad.String("10")}
// after
Values: []interface{}{quad.Int(10)}
Defensive patterns

Strategy: validation

Validate before calling

if (typeof limit !== 'number' || !Number.isInteger(limit)) throw new Error('limit/skip must be integers');

Type guard

func isQuadInt(v interface{}) bool { _, ok := v.(quad.Int); return ok }

Try / catch

out, err := iterateObject(ctx, qs, field, p)
if err != nil && strings.Contains(err.Error(), "unexpected value type") { /* coerce to quad.Int */ }

Prevention

When it happens

Trigger: A limit/skip value that is not a quad.Int — e.g. quad.String("10"), a float, or a boolean — passed in the Has constraint at query/graphql/graphql.go:177.

Common situations: Queries with quoted numbers (limit: "10"), JSON parsers producing float64 for integers that were never converted to quad.Int, or hand-built constraint lists in Go code.

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/ea2e4785220c21bd. Report an issue: GitHub.

Appendix: source

Thrown at query/graphql/graphql.go:177

	} else {
		p = p.LabelContext()
	}
	var (
		limit = -1
		skip  = 0
	)

	for _, h := range f.Has {
		switch h.Via {
		case quad.IRI(ValueKey): // special key - "id"
			p = p.Is(h.Values...)
		case quad.IRI(LimitKey), quad.IRI(SkipKey): // limit and skip
			if len(h.Values) != 1 {
				return nil, fmt.Errorf("unexpected arguments: %v (%d)", h.Values, len(h.Values))
			}
			n, ok := h.Values[0].(quad.Int)
			if !ok {
				return nil, fmt.Errorf("unexpected value type for %v: %T", string(h.Via), h.Values[0])
			}
			if h.Via == quad.IRI(LimitKey) {
				limit = int(n)
			} else {
				skip = int(n)
				if skip < 0 {
					skip = 0
				}
			}
		default: // everything else - Has constraint
			if len(h.Labels) != 0 {
				p = p.LabelContext(h.Labels)
			}
			if h.Rev {
				p = p.HasReverse(h.Via, h.Values...)
			} else {
				p = p.Has(h.Via, h.Values...)
			}

View on GitHub (pinned to 81dcd7d73e)