Using Conditional Breakpoints in GoLand for Precise Go Debugging
Learn how to add a conditional breakpoint in GoLand, see a worked example with a User struct, and understand the performance and configuration limits to avoid common debugging pitfalls.
27 Aug 2025, 14:21 UTC

Quick answer: add a conditional breakpoint in GoLand
\nIn GoLand you can make a breakpoint pause only when a Go expression evaluates to true. Right‑click the gutter beside the line you want to watch, choose Breakpoint → More…, tick Condition and type a valid Go expression (e.g. user.ID == 42 && strings.HasPrefix(user.Email, \"admin\")). The debugger will stop at that line only when the condition holds.
Worked example
\nConsider a tiny program that processes a slice of User values:
package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\ntype User struct {\n\tID int\n\tName string\n\tEmail string\n}\n\nfunc main() {\n\tusers := []User{\n\t\t{ID: 1, Name: \"alice\", Email: \"[contact removed]\"},\n\t\t{ID: 42, Name: \"admin\", Email: \"[contact removed]\"},\n\t\t{ID: 99, Name: \"bob\", Email: \"[contact removed]\"},\n\t}\n\tfor _, u := range users {\n\t\tfmt.Printf(\"processing %v\\n\", u)\n\t\t// do work\n\t}\n}\n\nSet a breakpoint on the line fmt.Printf(\"processing %v\\n\", u). Open the breakpoint dialog, enable Condition and enter:
u.ID == 42 && strings.HasPrefix(u.Email, \"admin\")\nStart debugging with Shift+F9 (or Run | Debug 'Go Build'). The debugger will pause only on the iteration where u.ID is 42 and the email starts with \"admin\". In the Variables pane you can inspect u and confirm the values.
Limits and common mistakes
\n- \n
- Performance impact. The condition is evaluated in the target process each time the line is reached. If the line sits inside a tight loop (e.g. millions of iterations) the overhead can be 10‑100×. For hot paths prefer logging or a sampling profiler. \n
- Missing debug information. Building with
-ldflags=\"-s -w\"orgo build -trimpathstrips DWARF symbols, making variable inspection and condition evaluation impossible. Always debug a binary built without those flags (the defaultgo buildworks). \n - Expression restrictions. The condition can call any accessible function or method, but it cannot allocate new goroutines, block on channels, or perform I/O that would change program state. If you need such side effects, use a regular breakpoint with logging instead. \n
- Wrong scope. If you reference a variable that is not in the current lexical scope (e.g. a package‑level variable from inside a method where it is shadowed), the condition will fail to compile and the breakpoint will never hit. Make sure the expression uses names visible at the breakpoint line. \n
- Inlining surprises. Starting with Go 1.22 the compiler may inline small functions, causing the debugger to step over the line you expect. If you notice the breakpoint never triggers, try rebuilding with
-gcflags=\"all=-N -l\"to disable inlining and verify. \n
How to verify the breakpoint works
\n- \n
- Set the conditional breakpoint as described. \n
- Start a debug session (Shift+F9). \n
- Open the Debug tool window and watch the Frames list. The program should stop only when the condition is true. \n
- When stopped, check the Variables pane for the expected values (e.g.
u.ID == 42). \n - Resume (F9) and confirm that the debugger does not stop on the other iterations. \n
If the breakpoint never stops, double‑check the condition syntax, ensure the binary was built with debug info, and verify that the line is actually being executed (add a temporary log.Println to confirm).
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.