Go Code Review with LGTM
AI code review for Go: LGTM catches ignored errors, shadowed variables in if-bodies, goroutine leaks, missing context.Context plumbing, unsafe nil-pointer derefs, and missing defer cleanup.
How LGTM reviews Go PRs
Tree-sitter parses every .go file in your repo, extracting funcs, methods, interfaces, structs, and the imports that connect them. Go's explicit import paths and exported-by-capitalisation rule make symbol extraction extremely clean — symbol resolution is more deterministic than in TypeScript or Python.
Per-PR: the 5-15 highest-PageRank-ranked symbols related to the diff get attached to agent prompts. The Bugs agent for Go focuses on the specific failure modes Go's design philosophy expects you to handle explicitly: error returns, context cancellation, goroutine lifecycle, channel closing.
Go's standard formatting (gofmt) means style debates are mostly settled. LGTM's Readability agent focuses on naming, function length, and the comment-driven godoc conventions that signal a well-maintained package.
Common Go bugs LGTM catches
Ignored errors. `data, _ := io.ReadAll(r)` — the `_` discards a real error. The Bugs agent flags every `_` assignment of an error return value, with a high-confidence finding because Go's design says errors are values to be checked.
Shadowed variables in if bodies. `if err := fn(); err != nil { ... }` is fine. `err := fn()` followed by `if err != nil { err := otherFn(); ... }` shadows the outer err — and the recovery logic silently uses wrong-scoped err. Flagged.
Goroutine leaks. `go fn()` where fn never returns and has no way to be signaled to stop. The Performance agent surfaces these especially in long-lived processes (servers, queue workers).
Missing context.Context plumbing. A function that does network I/O but takes no `ctx context.Context` parameter — uncancellable, untimeoutable. Flagged as anti-pattern in repos that use ctx elsewhere.
Nil-pointer derefs on interface receivers. `var p *Plugin; p.Init()` panics if Init isn't pointer-safe. The agent reads receiver definitions and flags interface-receiver calls without nil checks.
Missing defer for cleanup. `f, _ := os.Open(...)` without `defer f.Close()`. Filesystem leak. Caught by the Bugs agent.
Tree-sitter coverage for Go
Go's tree-sitter grammar is excellent — Go's syntax is small and unambiguous, parser produces clean trees.
Generics (Go 1.18+) parse correctly with type parameter declarations and constraints. Method sets with embedded interfaces resolve properly.
Go modules (go.mod) are read at index time to understand cross-package dependencies. Module path → import path → file path resolution lets the indexer build cross-package symbol graphs even in deeply nested monorepos.
cgo files (.go with // #cgo lines) parse the Go part; the embedded C is treated as opaque. C bugs in cgo aren't reviewed (that's a C agent's job — see the C++ glossary page).
Setup notes for Go projects
Install the LGTM GitHub App on the repo. Index time for typical Go services: 10-30 seconds. Large monorepos with many modules: 1-3 minutes.
go.mod and go.sum are detected automatically. Replace directives (for vendored or local modules) are honoured during import resolution.
Generated Go code (protoc output, ent-generated, mockgen) is auto-excluded by common heuristics (DO NOT EDIT headers, /generated/ paths). Custom-generated paths can be added to .lgtmignore.
Test files (_test.go) get reviewed — but with a different bar. Test code can have looser error handling (t.Fatal is fine), shorter naming, less docstring rigour. The agents adjust their bar by file naming conventions.
Example bugs LGTM catches
// ❌ Bug: inner err shadows outer; outer never sees real error
func update(id int) (err error) {
user, err := fetch(id)
if err != nil {
// recovery attempt
u, err := fallback(id) // <-- shadow!
if err != nil {
return err // returns INNER err
}
user = u
}
return saveUser(user)
}
// LGTM finding:
// "Inner 'err' shadows outer 'err' declared in named return.
// Use 'u, err = fallback(id)' (no shadowing) so the named
// return reflects the actual error path."// ❌ Bug: goroutine runs forever, no way to stop
func startWorker(jobs chan Job) {
go func() {
for {
job := <-jobs
process(job)
}
}()
}
// LGTM finding:
// "Goroutine has no exit path. Accept context.Context,
// select on ctx.Done() in the loop:
// for { select { case <-ctx.Done(): return; case job := <-jobs: ... } }"See LGTM's Go-aware review pipeline
Go module / generics / context-aware · BYOK
Go to the product pageGo review FAQs
Does LGTM run go vet or staticcheck?
No — LGTM is static analysis via tree-sitter + LLM reasoning, not execution of go vet. Run go vet + staticcheck in your CI; LGTM complements them by catching judgment-call patterns those tools miss (subtle shadowing in long functions, missing context plumbing, goroutine lifecycle).
What about cgo and assembly?
cgo Go-side parses cleanly; the C portion is opaque to the Go review. .s assembly files are not reviewed. If you're doing heavy cgo, those files won't get AI review — but they typically need a different review process anyway.
Generics support?
Yes — Go 1.18+ generics parse correctly. The agents reason about type constraints when surfacing findings about generic functions.
Multi-module monorepo support?
Yes. Each module's go.mod is detected. Cross-module references via replace directives or workspace mode (go.work) resolve to the local files when present.
Cost per Go review?
$0.05-$0.12 for a 300-line PR on GPT-4o via BYOK. Go's compact code style means typical diffs are smaller than Python or TypeScript equivalents — same fix often takes fewer lines, lowering token cost.
Related across LGTM
AI code review explained
Multi-agent review tuned to Go's idioms (error handling, context plumbing).
Tree-sitter explained
Why Go's compact grammar parses faster than most languages.
Pre-push CLI review
Run review on Go diffs locally — faster than goroutines starting.
BYOK on Gemini
Gemini Flash-Lite is the cheapest workable model for Go docs review.
Other languages
Rust
AI code review for Rust: LGTM catches lifetime annotation issues, unnecessary unsafe blocks, missed `?` short-circuits, Arc/Rc misuse, and panics in library code — beyond what the borrow checker flags.
TypeScript
AI code review for TypeScript: LGTM catches type-narrowing bugs, unsafe assertions, async race conditions, React stale-closure bugs, and unused exports — across the diff and the wider repo context.
Java
AI code review for Java: LGTM catches potential NPEs, mutable collection leaks from getters, thread-safety smells, missing equals/hashCode pairs, and Spring Boot anti-patterns.
C++
AI code review for C++: LGTM catches undefined behavior risks, dangling references, missing RAII patterns, integer overflow, smart-pointer misuse, and concurrency hazards in modern (C++17/20/23) code.