Skip to content
spot_the_ai_bug

Go (Golang) find-the-bug interview questions

Go interviews often hand you a short function and ask what goes wrong under load. These questions cover the classics: maps shared across goroutines, response bodies that never get closed, and edge cases that panic. Each has exactly one bug and a production-ready fix.

Go gotchas interviewers love

  • Maps are not safe for concurrent writes; guard them or use one per goroutine.
  • Always close resp.Body, even if you don't read it.
  • Integer division by zero panics.
  • Secrets in source code end up in every clone and fork.
  • Read boolean conditions twice; ! flips the whole meaning.

5 Go spot-the-bug questions

Each snippet has exactly one bug. Find the line before you open the answer.

Counting words in goroutines

CountWords splits work across goroutines. Under load the process dies with "fatal error: concurrent map writes". Why?

func CountWords(docs []string) map[string]int {	counts := make(map[string]int)	var wg sync.WaitGroup	for _, doc := range docs {		wg.Add(1)		go func(d string) {			defer wg.Done()			for _, w := range strings.Fields(d) {				counts[w]++			}		}(doc)	}	wg.Wait()	return counts}
Show answer

line 9 · Race condition

Go maps are not safe for concurrent writes. Several goroutines update counts at once, which the runtime detects and treats as a fatal error that can't be recovered.

Fix
	var mu sync.Mutex	// ... inside the goroutine:	for _, w := range strings.Fields(d) {		mu.Lock()		counts[w]++		mu.Unlock()	}

Interview follow-up: Better still: count into a local map per goroutine and merge at the end, so the lock is taken once per document.

Average of an empty slice

Average() is used on the latency dashboard. What happens for a service with no requests yet?

// Average returns the mean latency in milliseconds.func Average(latencies []int) int {	sum := 0	for _, l := range latencies {		sum += l	}	return sum / len(latencies)}
Show answer

line 7 · Wrong edge case

With an empty slice, len is 0 and integer division by zero panics at runtime ("integer divide by zero"), crashing the dashboard handler.

Fix
	if len(latencies) == 0 {		return 0	}	return sum / len(latencies)

Interview follow-up: Mention whether 0 is the right answer for "no data", or whether returning (int, bool) is clearer.

Unclosed HTTP response body

FetchStatus() is called every few seconds by a health checker. After a day the service runs out of file descriptors. Why?

func FetchStatus(client *http.Client, url string) (int, error) {	resp, err := client.Get(url)	if err != nil {		return 0, err	}	return resp.StatusCode, nil}
Show answer

line 2 · Resource leak

The response body is never closed. Each call leaves a connection and its file descriptor open, and they can't be returned to the pool, so the process eventually hits its open-file limit.

Fix
	resp, err := client.Get(url)	if err != nil {		return 0, err	}	defer resp.Body.Close()

Interview follow-up: Some interviewers also ask about draining the body (io.Copy(io.Discard, resp.Body)) so keep-alive connections can be reused.

Hard-coded JWT signing key

This signs session tokens for the API. What should block this PR?

var jwtSecret = []byte("super-secret-change-me") func SignToken(userID string) (string, error) {	claims := jwt.MapClaims{		"sub": userID,		"exp": time.Now().Add(24 * time.Hour).Unix(),	}	return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString(jwtSecret)}
Show answer

line 1 · Leaked secret

The signing key is in source control. Anyone who can read the repo (or a leaked copy) can mint valid tokens for any user, including admins. Load it from a secret store or environment at startup, and fail if it's missing.

Fix
var jwtSecret = mustEnv("JWT_SECRET") func mustEnv(key string) []byte {	v := os.Getenv(key)	if v == "" {		log.Fatalf("%s is not set", key)	}	return []byte(v)}

Interview follow-up: Mention key rotation and that a guessable HS256 secret can be brute-forced offline from any issued token.

Upload file-type check

validateUpload() should only accept PNG files. What does it actually allow?

var errNotPNG = errors.New("only .png files are allowed") func validateUpload(filename string) error {	if !strings.HasSuffix(strings.ToLower(filename), ".png") {		return nil	}	return errNotPNG}
Show answer

line 4 · Logic inverted

The condition is inverted: every file that is not a PNG passes validation, and real PNGs are rejected.

Fix
	if strings.HasSuffix(strings.ToLower(filename), ".png") {		return nil	}	return errNotPNG

Interview follow-up: Also point out that extensions are user-controlled; check the file's magic bytes (http.DetectContentType) for real validation.

Every day, everyone gets the same pull request written by AI. It looks clean. It has comments. It has exactly one real bug.

  1. 1

    Find the line

    Tap the buggy line, then hit Submit. You get 3 attempts.

  2. 2

    Read the hints

    A miss within 2 lines is 🔥 Warm. Anything further is ❄️ Cold.

  3. 3

    Name the bug

    Found it? Bonus round: pick the bug type from 4 options. It doesn't affect your win, just your bragging rights.

// your share card

found in 3/3

🟥 cold miss · 🟨 warm miss · 🟩 found · ⬛ unused

Keyboard: ↑ ↓ to move between lines, Enter to submit. A new bug drops every day at midnight IST.

0
Played
0
Win %
0
Streak
0
Max

Attempts distribution