{"record":{"id":"fe924e10fef5d1b1","repo":"go-delve/delve","slug":"s-s-can-only-be-used-at-toplevel","errorCode":null,"errorMessage":"%s.%s can only be used at toplevel","messagePattern":"(.+?)\\.(.+?) can only be used at toplevel","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/proc/evalop/evalcompile.go","lineNumber":300,"sourceCode":"\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif depth[len(ctx.ops)] != endDepth {\n\t\treturn fmt.Errorf(\"internal debugger error: depth check failed: depth at the end is not %d (got %d)\\n%s\", depth[len(ctx.ops)], endDepth, Listing(depth, ctx.ops))\n\t}\n\treturn nil\n}\n\nfunc (ctx *compileCtx) compileAST(t ast.Expr, toplevel bool) error {\n\tswitch node := t.(type) {\n\tcase *ast.CallExpr:\n\t\tif f, ok := node.Fun.(*ast.SelectorExpr); ok && ctx.flags&BreakpointCondition != 0 {\n\t\t\tconst catch = \"catch\"\n\t\t\tif ident, ok := f.X.(*ast.Ident); ok && ident.Name == DelvePackage && f.Sel.Name == catch {\n\t\t\t\tif !toplevel {\n\t\t\t\t\treturn fmt.Errorf(\"%s.%s can only be used at toplevel\", DelvePackage, catch)\n\t\t\t\t}\n\t\t\t\tif len(node.Args) != 1 {\n\t\t\t\t\treturn fmt.Errorf(\"wrong number of arguments for %s.%s\", DelvePackage, catch)\n\t\t\t\t}\n\t\t\t\tctx.pushOp(&DisableErrors{})\n\t\t\t\treturn ctx.compileAST(node.Args[0], false)\n\t\t\t}\n\t\t}\n\t\treturn ctx.compileTypeCastOrFuncCall(node, toplevel)\n\n\tcase *ast.Ident:\n\t\treturn ctx.compileIdent(node)\n\n\tcase *ast.ParenExpr:\n\t\t// otherwise just eval recursively\n\t\treturn ctx.compileAST(node.X, false)\n\n\tcase *ast.SelectorExpr: // <expression>.<identifier>","sourceCodeStart":282,"sourceCodeEnd":318,"githubUrl":"https://github.com/go-delve/delve/blob/a23773e6c31361e43246bc43a424ee009679b174/pkg/proc/evalop/evalcompile.go#L282-L318","documentation":"Delve provides a special `delve.catch(...)` expression usable in breakpoint conditions to suppress errors from function-call injection. It is only valid as a whole top-level expression; the compiler rejects it when it appears nested inside a larger expression (e.g. as an operand), because error suppression cannot be scoped to a sub-expression.","triggerScenarios":"Compiling a breakpoint condition or eval expression where a `delve.catch` call appears anywhere other than the top level: `x == delve.catch(f())`, `delve.catch(f()) + 1`, inside parens of another expression, or inside another call's argument list.","commonSituations":"Users write arithmetic or comparisons around delve.catch expecting it to behave like a normal function; conditions copied from examples get combined with other predicates.","solutions":["Make delve.catch the entire top-level expression and move surrounding logic inside its argument or into the called function","Wrap the comparison itself: `delve.catch(x == f())` instead of `x == delve.catch(f())`","Do the arithmetic/comparison inside a helper function that delve.catch then calls"],"exampleFix":"// before (nested -> rejected)\ncondition 1 x == delve.catch(f())\n// after (toplevel)\ncondition 1 delve.catch(x == f())","handlingStrategy":"validation","validationCode":"// Validate the condition shape before setting it:\nfunc isToplevelCatch(cond string) bool {\n    expr, err := parser.ParseExpr(cond)\n    if err != nil { return false }\n    call, ok := expr.(*ast.CallExpr)\n    if !ok { return false }\n    sel, ok := call.Fun.(*ast.SelectorExpr)\n    id, _ := sel.X.(*ast.Ident)\n    return ok && id != nil && id.Name == \"delve\" && sel.Sel.Name == \"catch\"\n}","typeGuard":null,"tryCatchPattern":"if err := setBreakpointCondition(bp, cond); err != nil &&\n    strings.Contains(err.Error(), \"can only be used at toplevel\") {\n    // rewrite condition: move outer logic inside delve.catch(...)\n    return setBreakpointCondition(bp, \"delve.catch(\"+inner+\")\")\n}","preventionTips":["Remember delve.catch must wrap the ENTIRE condition expression","Never nest delve.catch inside arithmetic, comparisons, or other calls","Read it as a statement-level wrapper, not a normal function"],"tags":["debugger","eval","delve-catch","breakpoint-condition"],"backgroundTag":"delve-catch-misuse","analyzedSha":"a23773e6c31361e43246bc43a424ee009679b174","analyzedAt":"2026-08-31T15:12:45.221Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}