{"record":{"id":"17812644fde97bc4","repo":"cayleygraph/cayley","slug":"too-many-close-parentheses-at-char-d-s","errorCode":null,"errorMessage":"too many close parentheses at char %d: %s","messagePattern":"too many close parentheses at char (.+?): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"query/sexp/session.go","lineNumber":62,"sourceCode":"\nfunc NewSession(qs graph.QuadStore) *Session {\n\treturn &Session{qs: qs}\n}\n\nfunc (s *Session) Parse(input string) error {\n\tvar parenDepth int\n\tfor i, x := range input {\n\t\tif x == '(' {\n\t\t\tparenDepth++\n\t\t}\n\t\tif x == ')' {\n\t\t\tparenDepth--\n\t\t\tif parenDepth < 0 {\n\t\t\t\tmin := 0\n\t\t\t\tif (i - 10) > min {\n\t\t\t\t\tmin = i - 10\n\t\t\t\t}\n\t\t\t\treturn fmt.Errorf(\"too many close parentheses at char %d: %s\", i, input[min:i])\n\t\t\t}\n\t\t}\n\t}\n\tif parenDepth > 0 {\n\t\treturn query.ErrParseMore\n\t}\n\tif len(ParseString(input)) > 0 {\n\t\treturn nil\n\t}\n\treturn errors.New(\"invalid syntax\")\n}\n\nfunc (s *Session) Execute(ctx context.Context, input string, opt query.Options) (query.Iterator, error) {\n\tswitch opt.Collation {\n\tcase query.Raw, query.REPL:\n\tdefault:\n\t\treturn nil, &query.ErrUnsupportedCollation{Collation: opt.Collation}\n\t}","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/cayleygraph/cayley/blob/81dcd7d73e45136bc0d01802a8ba4685d8a533eb/query/sexp/session.go#L44-L80","documentation":"The s-expression parser for query languages tracks parenthesis depth while scanning input. If a ')' appears when parenDepth is already 0, the input is malformed, so Parse returns this error with the character offset and a snippet of the input up to that point.","triggerScenarios":"Calling Parse (query/sexp/session.go) on a query string containing more ')' than '(' before it, e.g. \":a))\" or an unbalanced template-generated expression.","commonSituations":"Hand-written s-expression queries; programmatic query builders that append extra closing parens; copy-paste errors that drop an opening paren.","solutions":["Count parens in the query and remove the extra ')' indicated by the char offset in the message.","Parse incrementally / build queries with a helper that balances parens.","If input may legitimately be incomplete, check for query.ErrParseMore semantics and feed more input instead."],"exampleFix":"// before\nq := \"(start))\"\n// after\nq := \"(start)\"","handlingStrategy":"validation","validationCode":"func balanced(s string) bool {\n    d := 0\n    for _, r := range s {\n        if r == '(' { d++ } else if r == ')' { d-- }\n        if d < 0 { return false }\n    }\n    return d == 0\n}\nif !balanced(q) { /* fix input before Parse */ }","typeGuard":"func isBalancedSexp(s string) bool { d := 0; for _, r := range s { if r == '(' { d++ }; if r == ')' { d-- }; if d < 0 { return false } }; return d == 0 }","tryCatchPattern":"it, err := sess.Parse(q)\nif err != nil {\n    if errors.Is(err, query.ErrParseMore) { /* feed more input */ }\n    if strings.Contains(err.Error(), \"too many close parentheses\") {\n        // parse offset from message, repair input\n    }\n    return err\n}","preventionTips":["Build s-expressions with a writer that tracks paren depth.","Lint queries for balanced parens before sending.","Avoid hand-editing generated s-expression queries."],"tags":["go","parser","sexp","syntax"],"backgroundTag":"invalid-argument-format","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"}