{"record":{"id":"b888dc78dc4bb880","repo":"cayleygraph/cayley","slug":"optional-iterator-at-the-top-level","errorCode":null,"errorMessage":"optional iterator at the top level","messagePattern":"optional iterator at the top level","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"query/mql/build_iterator.go","lineNumber":51,"sourceCode":"\treturn shape.Save{\n\t\tFrom: shape.AllNodes{},\n\t\tTags: []string{string(path)},\n\t}\n}\n\nfunc (q *Query) BuildIteratorTree(ctx context.Context, query interface{}) {\n\tq.isRepeated = make(map[Path]bool)\n\tq.queryStructure = make(map[Path]map[string]interface{})\n\tq.queryResult = make(map[ResultPath]map[string]interface{})\n\tq.queryResult[\"\"] = make(map[string]interface{})\n\n\tvar (\n\t\topt bool\n\t\ts   shape.Shape\n\t)\n\ts, opt, q.err = q.buildShape(query, NewPath())\n\tif q.err == nil && opt {\n\t\tq.err = errors.New(\"optional iterator at the top level\")\n\t}\n\tq.it = shape.BuildIterator(ctx, q.ses.qs, s)\n}\n\nfunc (q *Query) buildShape(query interface{}, path Path) (s shape.Shape, optional bool, err error) {\n\terr = nil\n\toptional = false\n\tswitch t := query.(type) {\n\tcase bool:\n\t\t// for JSON booleans\n\t\ts = shape.Lookup{quad.Bool(t)}\n\tcase float64:\n\t\t// for JSON numbers\n\t\t// Damn you, Javascript, and your lack of integer values.\n\t\tif math.Floor(t) == t {\n\t\t\t// Treat it like an integer.\n\t\t\ts = shape.Lookup{quad.Int(t)}\n\t\t} else {","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/cayleygraph/cayley/blob/81dcd7d73e45136bc0d01802a8ba4685d8a533eb/query/mql/build_iterator.go#L33-L69","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nquery := `[{\"@optional\": \"name\"}]`\n// after\nquery := `[{\"name\": [], \"@optional\": \"@optional:name\"}]` // or place @optional on nested field","handlingStrategy":"validation","validationCode":"var parsed []interface{}\njson.Unmarshal([]byte(mqlQuery), &parsed)\nfor _, item := range parsed {\n    if m, ok := item.(map[string]interface{}); ok {\n        if _, has := m[\"@optional\"]; has && len(m) <= 2 {\n            return errors.New(\"@optional must be nested, not top-level\")\n        }\n    }\n}","typeGuard":"func isTopLevelOptional(q []interface{}) bool {\n    for _, v := range q {\n        if m, ok := v.(map[string]interface{}); ok {\n            if _, has := m[\"@optional\"]; has { return true }\n        }\n    }\n    return false\n}","tryCatchPattern":"it, err := session.Execute(ctx, mqlQuery, nil)\nif err != nil && strings.Contains(err.Error(), \"optional iterator at the top level\") {\n    return fmt.Errorf(\"restructure query: @optional cannot be at root\")\n}","preventionTips":["Keep @optional on nested fields only","Validate MQL JSON structure before Execute","Write tests covering each query template used in production"],"tags":["go","mql","query","optional"],"backgroundTag":"invalid-argument-value","analyzedSha":"81dcd7d73e45136bc0d01802a8ba4685d8a533eb","analyzedAt":"2026-09-06T06:14:12.358Z","contentChangedAt":"2026-09-06T06:14:12.358Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}