cayleygraph/cayley · error
optional iterator at the top level
Error message
optional iterator at the top level
What it means
In the MQL query session, an @optional directive is only meaningful nested inside a structure. If the top-level query shape resolves as optional, BuildIteratorTree rejects it because there is no outer context in which 'optionality' can be applied.
Source
Thrown at query/mql/build_iterator.go:51
return shape.Save{
From: shape.AllNodes{},
Tags: []string{string(path)},
}
}
func (q *Query) BuildIteratorTree(ctx context.Context, query interface{}) {
q.isRepeated = make(map[Path]bool)
q.queryStructure = make(map[Path]map[string]interface{})
q.queryResult = make(map[ResultPath]map[string]interface{})
q.queryResult[""] = make(map[string]interface{})
var (
opt bool
s shape.Shape
)
s, opt, q.err = q.buildShape(query, NewPath())
if q.err == nil && opt {
q.err = errors.New("optional iterator at the top level")
}
q.it = shape.BuildIterator(ctx, q.ses.qs, s)
}
func (q *Query) buildShape(query interface{}, path Path) (s shape.Shape, optional bool, err error) {
err = nil
optional = false
switch t := query.(type) {
case bool:
// for JSON booleans
s = shape.Lookup{quad.Bool(t)}
case float64:
// for JSON numbers
// Damn you, Javascript, and your lack of integer values.
if math.Floor(t) == t {
// Treat it like an integer.
s = shape.Lookup{quad.Int(t)}
} else {View on GitHub (pinned to 81dcd7d73e)
Solutions
- Remove @optional from the top-level object and keep it only on nested fields.
- Restructure the query so the optional clause is nested under a required parent node.
- If everything should be optional, select fields explicitly without the optional directive.
Example fix
// before
query := `[{"@optional": "name"}]`
// after
query := `[{"name": [], "@optional": "@optional:name"}]` // or place @optional on nested field Defensive patterns
Strategy: validation
Validate before calling
var parsed []interface{}
json.Unmarshal([]byte(mqlQuery), &parsed)
for _, item := range parsed {
if m, ok := item.(map[string]interface{}); ok {
if _, has := m["@optional"]; has && len(m) <= 2 {
return errors.New("@optional must be nested, not top-level")
}
}
} Type guard
func isTopLevelOptional(q []interface{}) bool {
for _, v := range q {
if m, ok := v.(map[string]interface{}); ok {
if _, has := m["@optional"]; has { return true }
}
}
return false
} Try / catch
it, err := session.Execute(ctx, mqlQuery, nil)
if err != nil && strings.Contains(err.Error(), "optional iterator at the top level") {
return fmt.Errorf("restructure query: @optional cannot be at root")
} Prevention
- Keep @optional on nested fields only
- Validate MQL JSON structure before Execute
- Write tests covering each query template used in production
When it happens
Trigger: Running a MQL query whose root node uses @optional (or otherwise resolves to an optional shape), e.g. [{"@optional": ...}] at the top level of the query JSON.
Common situations: Copy-pasting a nested @optional clause to the top level; hand-writing MQL JSON with optional at the root when the user actually wanted all fields optional.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- multiple fields at location root %s
- Unknown JSON type: %T
- cannot count iterator without a valid context
- node tokens not valid
- varint: overflow
AI-assisted analysis of cayleygraph/cayley@81dcd7d73e (2026-09-06).
Data as JSON: /api/errors/b888dc78dc4bb880.
Report an issue: GitHub.