agentsclimarketplace

Debug go

Skill yerdaulet-damir/vibe-coding-rules/.claude/skills/debug-go

54 production architecture rules for vibe coding with Claude Code & Cursor. Drop-in CLAUDE.md, .cursor/rules, and .claude/skills for FastAPI, Next.js 15, and Go 1.22+ — turn AI-assisted coding from prototype hack to production.

Install
npx -y skills add yerdaulet-damir/vibe-coding-rules --skill debug-go

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 8 stars8 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Systematic 5-step debugging flow for Go 1.22+ services. Load when a test fails, a goroutine leaks, a downstream provider hangs, errors lose context, or production logs are unhelpful. Forces layer isolation (handler vs service vs repo vs provider) and runs the 5 most common Go antipattern greps before any code change — prevents the "add a goroutine to fix a slow handler" cascade.

SKILL.md

7.0 KB, as published. Nobody here has run it

debug-go

Stop. Do not edit any file yet. Work through these 5 steps in order.


Step 1 — Locate the layer

Go bugs almost always live in one of these layers. Identify which one before touching code.

SymptomLikely layerFirst grep
500 in prod, no useful logHandler — error mappinggrep -n "errors.Is|errors.As" internal/server/handlers.go
Wrong amount / state after mutationService / repogrep -n "Hold|Confirm|Refund" internal/<domain>/service.go
Hangs under loadHTTP client / bulkheadgrep -rn "http.DefaultClient|MaxConnsPerHost" internal/
context deadline exceeded everywhereMissing ctx propagationgrep -rn "context.Background()|context.TODO()" internal/
Goroutine leak in pproferrgroup not used / unclosed channelsgrep -rn "go func\b" internal/
Test passes locally, race on CIShared mutable statego test ./... -race
Panic crashes serverMissing recover middlewaregrep -rn "recover()" internal/server/
Downstream API change broke usProvider parsergrep -rn "json.Unmarshal|json.NewDecoder" internal/providers/

Pick one layer. Do not touch any other layer in this debug pass.


Step 2 — Run the 5 most common Go antipattern greps

# Antipattern 1: http.DefaultClient (no per-provider isolation)
grep -rn "http\.DefaultClient" internal/

# Antipattern 2: context.Background() / context.TODO() in non-main code
grep -rn "context\.Background()\|context\.TODO()" internal/ \
  --include="*.go" | grep -v "_test.go"

# Antipattern 3: panic in production code
grep -rn "panic(" internal/ --include="*.go" | grep -v "_test.go\|recover"

# Antipattern 4: fmt.Println / log.Printf instead of slog
grep -rn "fmt\.Println\|log\.Printf" internal/ --include="*.go" | grep -v "_test.go"

# Antipattern 5: errors not wrapped with %w
grep -rn "errors\.New(\"[^%]*: \"" internal/ --include="*.go"
# Hits with concatenation suggest a missed `%w` opportunity.
ResultRoot causePrinciple
http.DefaultClient usedBulkhead broken — one slow downstream blocks allF4
context.Background() in handler chainLost cancellation/deadline propagationF2
panic() in handler/serviceServer crashes on edge caseF3
fmt.Println/log.PrintfLogs without context, unsearchableF6
errors.New with concatenated contextLost error chain, errors.Is/As failsF3

Step 3 — Reproduce with go test -run and -race

For service/repo bugs — write a failing test first:

func TestService_RaceOnConcurrentCharge(t *testing.T) {
    t.Parallel()
    svc := newTestService(t, dec("10.00"))
    ctx := context.Background()

    // Two concurrent charges with the same idempotency key.
    // Should hold once, not twice.
    var wg sync.WaitGroup
    var ids [2]string
    for i := 0; i < 2; i++ {
        i := i
        wg.Add(1)
        go func() {
            defer wg.Done()
            id, _ := svc.Charge(ctx, "u-1", dec("4.00"), "idem-x")
            ids[i] = id
        }()
    }
    wg.Wait()
    if ids[0] != ids[1] {
        t.Fatalf("idempotency violated: %s vs %s", ids[0], ids[1])
    }
}

Run it:

go test -run TestService_RaceOnConcurrentCharge -race -v ./internal/credits/

It must FAIL before the fix.

For HTTP client / provider bugs — use httptest.Server to simulate the failure:

srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusTooManyRequests)
}))
defer srv.Close()

p := &FalAI{client: srv.Client(), baseURL: srv.URL, log: slog.Default()}
_, err := p.Generate(context.Background(), JobRequest{ModelID: "m", Prompt: "p"})
if !errors.Is(err, ErrRateLimited) {
    t.Fatalf("expected ErrRateLimited, got %v", err)
}

Step 4 — Fix in the correct layer

Minimum change. Do not refactor unrelated code.

LayerWhere to fix
Handler / error → HTTP codeinternal/server/handlers.go
Business logicinternal/<domain>/service.go
Persistence / concurrencyinternal/<domain>/repository.go
External API parsinginternal/providers/<name>.go (the ACL)
HTTP client configinternal/httpclient/client.go
Logging contextinternal/context/keys.go + middleware
Graceful shutdowninternal/server/run.go

Goroutine leaks specifically: add errgroup with a parent context.WithCancel. Every go func should be replaceable by g.Go(func() error { ... }). (Principle F8.)


Step 5 — Verify

# Type / vet check
go vet ./...

# Race detector — catches concurrency bugs you can't see by reading
go test ./... -race

# All tests pass
go test ./...

# (If you have a linter)
golangci-lint run

Then re-run all 5 antipattern greps from Step 2. You must not have introduced any new violations while fixing.


Common error → root cause table

Error / SymptomWhere to lookLikely cause
runtime error: invalid memory addressnil pointerA struct field not initialized — check the constructor
concurrent map read and writeshared mutable mapAdd sync.Mutex or use sync.Map if read-heavy
context deadline exceeded cascading everywhereparent ctxProbably a fixed context.WithTimeout(ctx, 1s) upstream
dial tcp: i/o timeoutnetwork or DNSCheck provider client Timeout; check pod DNS
too many open filesFD exhaustionBulkhead violation (F4): a hung downstream eating the pool
Test hangs foreverUnbuffered channelProducer goroutine exited without sending; receiver waits forever
interface conversion: ... is not ...wrong concrete typeHandler accepts a too-wide interface; tighten with the smallest method set
Panic mid-request, server stays up but log is silentrecover swallowsMake sure the recover middleware logs rec and debug.Stack()
Server doesn't drain on SIGTERMsignal.Notify not wiredUse signal.NotifyContext (Go 1.16+) — Principle F7
Provider response field appears null after parseUnmarshal hit zero valueCheck JSON tag spelling; use *string if true-null matters

Verification

The skill was applied correctly when:

  • A reproducible test exists (Step 3) — failing before, passing after
  • Fix touches exactly one layer
  • All 5 antipattern greps still come up clean
  • go vet ./... && go test ./... -race exits 0
  • No new file exceeds 500 LOC; no new package named utils/helpers/common

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.