
These eight Golang interview questions help backend and platform candidates explain slices, interfaces, channel ownership, cancellation, and errors. Predict each result before reading the answer, then practice the follow-up aloud. Two short scenarios cover dependency failures and shutdown. This is focused practice, rather than an exhaustive Go question bank.
Verification — October 24, 2026: The complete examples were executed locally with Go 1.26.4 on Windows amd64 using an AI-assisted tool workflow; Emma is the article editor. Outputs marked Verified run were observed in that environment. With cgo enabled and GCC 16.2.0 / MinGW-w64 14.0.0, four worker cancellation and completion tests each passed 20 runs under the race detector. A deliberately racy control program triggered a warning. This checks the exercised paths, not every possible interleaving. The exercises are original teaching practice, not employer questions. Language explanations were checked against the Go specification, pipeline guide, and race detector documentation.
SkillCopilotAI offers the optional practice tool mentioned below. The cover is an AI-generated editorial illustration, not a product screenshot.
To reproduce an example, save its complete Go code as main.go and run go run main.go. Run each example separately, since each declares its own main function. The worker pool's job order and count vary with scheduling.
Quick answer map
| Question | Common trap | One-line answer |
|---|---|---|
Q1 Slice append | “Slices always copy” | Shared backing array + spare capacity → append can mutate the other variable |
Q2 Interface nil | “Nil pointer in interface is nil” | Typed nil keeps a type word; c == nil is false |
| Q3 Who closes | “Any reader may close” | Only the sending side (or one coordinator after all senders finish) closes |
Q6 go test -race | “Clean once means no races” | Reports races only on paths that ran; evidence, not a proof |
| Q7 Defer args | “Everything is evaluated at exit” | Arguments are evaluated when defer is registered; closures see later mutations |
What Go interviews usually probe
| Area | What “good” sounds like |
|---|---|
| Language traps | Slice aliasing, nil maps, typed-nil interfaces, defer argument timing |
| Concurrency | Goroutine lifecycle, channel ownership, select, context cancel, races |
| Correctness under failure | Timeouts, partial work, idempotent retries (design talk) |
| Testing | Table-driven tests, go test -race, when a clean race run is not proof |
If you only memorize “goroutines are lightweight threads,” you will stall on the first follow-up. Practice exit conditions.
Part 1 — Core Golang interview questions
Q1. After this append, what is in a?
package main
import "fmt"
func main() {
a := []int{1, 2, 3}
b := a[:2]
b = append(b, 99)
fmt.Printf("a=%v b=%v\n", a, b)
}Strong answer: b is a slice header into the same backing array as a, with length 2 and capacity 3. append still fits in capacity, so it writes 99 into index 2 of the shared array. Both a and b show 99.
Verified run (2026-10-24, go run, Go 1.26.4, Windows amd64):
a=[1 2 99] b=[1 2 99]Wrong answer: “Slices always copy, so a stays [1 2 3].” That confuses array value semantics with slice headers.
Follow-up: “How do you force a copy so append cannot mutate a?”
Expect: a full copy (append([]int(nil), a[:2]...)) or a full-slice expression that sets capacity equal to length (a[:2:2]) before append.
Self-check cue: Say “header + backing array + capacity,” not just “reference type.”
Q2. Is this interface value nil?
package main
import "fmt"
type Closer interface{ Close() error }
type File struct{}
func (f *File) Close() error { return nil }
func main() {
var f *File = nil
var c Closer = f
fmt.Printf("c==nil? %v (type=%T)\n", c == nil, c)
}Strong answer: f is a nil *File. Assigning it to Closer stores a typed pair (type=*File, value=nil). The interface value itself is not nil, because its type word is set. Calling c.Close() can still be safe if the method tolerates a nil receiver; comparing c == nil is false.
Verified run (2026-10-24, go run, Go 1.26.4, Windows amd64):
c==nil? false (type=*main.File)Wrong answer: “Any nil pointer assigned to an interface stays nil.” That classic trap breaks error returns like return err when err is a typed nil.
Follow-up: “How would you return a real nil error from a function that uses a concrete error pointer type?”
Expect: var err error = nil / bare return nil, not return (*MyError)(nil).
Q3. Who should close this channel?
package main
import "fmt"
func main() {
ch := make(chan string, 2)
go func() {
defer close(ch) // sender closes
ch <- "ok"
ch <- "done"
}()
for v := range ch {
fmt.Println(v)
}
}Strong answer: Only the sending side (or a single coordinator after all senders finish) should close. Receivers range until close. Closing twice, closing a nil channel, or sending on a closed channel panics.
Verified run (2026-10-24, go run, Go 1.26.4, Windows amd64):
ok
doneWrong answer: “Any goroutine can close when it is done reading.” That races and panics under load.
Follow-up: “Two producers write to one channel. Who closes?”
Expect: a WaitGroup (or errgroup) among producers, then one closer; or a separate merger stage.
Part 2 — Golang concurrency interview questions
Q4. Design a tiny worker pool that respects cancellation
Prompt: Two workers pull jobs from a channel. A 50ms deadline should request cancellation of the pool—even if jobs remain.
The worker must observe cancellation while waiting for a job as well as during work. This runnable example also makes producer sends cancelable, so an unbuffered job channel cannot leave the producer blocked after workers exit.
package main
import (
"context"
"fmt"
"sync"
"time"
)
func worker(ctx context.Context, jobs <-chan int, wg *sync.WaitGroup) {
defer wg.Done()
for {
select {
case <-ctx.Done():
return
case j, ok := <-jobs:
if !ok || ctx.Err() != nil {
return
}
timer := time.NewTimer(30 * time.Millisecond)
select {
case <-ctx.Done():
timer.Stop()
return
case <-timer.C:
if ctx.Err() != nil {
return
}
fmt.Println("done job", j)
}
}
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
defer cancel()
jobs := make(chan int)
var wg sync.WaitGroup
for w := 0; w < 2; w++ {
wg.Add(1)
go worker(ctx, jobs, &wg)
}
produce:
for i := 1; i <= 5; i++ {
select {
case <-ctx.Done():
break produce
case jobs <- i:
}
}
close(jobs)
wg.Wait()
fmt.Printf("ctx.Err=%v\n", ctx.Err())
}What interviewers listen for:
- Cancellation is cooperative — workers must
selectonctx.Done(). - The job channel still has a clear owner (producer closes).
- You can explain leftover jobs: canceled work is acceptable if the API documents it.
Evidence note: Job lines such as done job N are illustrative only—count and order depend on scheduling, so they are not a Verified run. The ctx.Err line below was observed once in the local test environment (Go 1.26.4, Windows amd64, 2026-10-24) after the 50ms deadline; treat it as a representative cancellation outcome, not a fixed job transcript.
Example cancellation outcome: Workers may finish jobs 1 and 2 before cancellation; timing and order vary. The deadline requests cooperative shutdown rather than guaranteeing that every goroutine stops at exactly 50ms. When multiple select cases are ready, cancellation has no automatic priority.
ctx.Err=context deadline exceededReal blocking I/O must receive the context too; a timer cannot interrupt an arbitrary function. See the official pipeline cancellation guide for ownership and exit-path reasoning.
Race-tested scope: The local tests covered cancellation while waiting on an open, empty channel; cancellation after receiving a job; an already closed channel; and completing buffered jobs normally. Each passed 20 repetitions with go test -race -count=20. No race was reported on those executions; that result is not a proof of correctness for untested paths or modified versions.
Wrong answer: “I spawn a goroutine per request with no limit and ignore context.” That leaks work and invites thundering herds.
Follow-up: “Buffered vs unbuffered jobs—what changes under backpressure?”
Expect: unbuffered blocks the producer on a busy worker (natural backpressure); large buffers hide overload until memory or latency blows up.
Q5. Mutex or channel for a shared counter?
Strong answer: For a single independent counter, consider atomic or a small Mutex; benchmark if performance matters. Use a channel when you are transferring ownership of data or coordinating stages (pipeline, fan-in). “Share memory by communicating” is a design preference, not a ban on locks.
Wrong answer: “Never use mutexes in Go.” You will fight the race detector and the standard library.
Follow-up: “Show how WaitGroup misuse causes a panic.”
Expect: an extra Done can panic with a negative counter. Calling Add inside a newly started goroutine can instead let Wait return before that goroutine registers; this does not necessarily panic.
Q6. What does go test -race actually guarantee?
Strong answer: It instruments memory accesses and reports races on paths that ran. A clean run is evidence, not a proof. Pair it with tests that force concurrent writers and readers.
Wrong answer: “If -race is clean once, the package cannot race.”
Follow-up: “How do you reproduce a flaky race locally?”
Expect: more -count, stress tests, and sometimes GOMAXPROCS variation—not only re-running the happy path.
Part 3 — Errors, defer, and API-shaped questions
Q7. Wrap, errors.Is, and when to panic
Strong answer: Return error for expected failure. Wrap with %w to keep the chain. Use errors.Is / errors.As at boundaries. Reserve panic for “this program is wrong,” and recover only at a supervisor edge (HTTP server, worker loop)—not sprinkled through business logic.
Wrong answer: “Panic instead of returning errors; it is cleaner.”
Follow-up: “Defer: are arguments evaluated now or at function exit?”
Expect: arguments evaluated when defer is registered; closures see later mutations.
package main
import "fmt"
func demonstrateDefer() {
n := 1
defer fmt.Println("argument:", n) // captures 1 now
defer func() { fmt.Println("closure:", n) }()
n = 2
}
func main() {
demonstrateDefer()
}Verified run (2026-10-24, go run, Go 1.26.4, Windows amd64; LIFO order):
closure: 2
argument: 1Q8. Interface design for testability
Strong answer: Define small interfaces in the consumer package, for example type UserStore interface { Get(ctx context.Context, id string) (User, error) }. Return concrete types from constructors. This keeps mocks tiny and avoids “enterprise” interface bloat.
Wrong answer: “Export a 20-method interface in the producer package for every struct.”
Follow-up: “Value vs pointer receivers—when does a value fail to satisfy an interface?”
Expect: pointer-receiver methods are not in the method set of T, only *T.
Part 4 — Mini scenarios (oral and whiteboard)
Scenario A — Slow dependency
“Your handler fans out to three services. One hangs. What do you do?”
Outline answer (say it in this order):
- Derive a child context with a deadline from the request context and pass it to every outbound call.
- Set HTTP/client timeouts that are shorter than the parent deadline so you fail before the handler itself times out.
- Prefer
errgroup.WithContext(or equivalent) so one hard failure cancels siblings instead of leaking goroutines. - Label each dependency required vs optional, and state fail-open vs fail-closed before coding.
- Log which dependency canceled the group and whether partial results are returned.
Wrong answer: “Wait forever; the load balancer will save us.”
Scenario B — Shutdown
“Kubernetes sends SIGTERM. What must stop?”
Outline answer (say it in this order):
- Stop admitting new work (
http.Server.Shutdownor equivalent) while finishing in-flight requests up to a budget. - Cancel the root worker context so pools exit cooperatively on
ctx.Done(). - Decide drain vs abandon for leftover jobs from the SLA—not from hope.
- Stop admitting jobs and coordinate all senders finishing before the single channel owner closes
jobs. If workers exit through cancellation, blocked producer sends must also observe cancellation; do not close a channel while another goroutine can still send. - Keep the shutdown timeout at least as long as the longest acceptable request, and verify no goroutine is blocked on an unbuffered send after cancel.
Self-check before the interview
Say these out loud without notes:
- Why can
appendmutate another slice variable? - Why is a typed-nil interface not
nil? - Who closes a channel when there are two senders?
- Name three cooperative cancel points in a worker loop.
- What does a clean
go test -racenot prove? - When would you pick
Mutexover a channel? - How do you keep an HTTP client from ignoring the request deadline?
If any answer is fuzzy, re-run the matching snippet and explain the output—or rehearse the same questions in a timed mock.
Frequently asked questions
Are these real company interview questions?
No. They are original teaching exercises built around common Go language and concurrency traps. Use them to practice explanation quality, not to memorize a leaked bank.
Is a clean go test -race enough?
No. It only reports races on paths that executed (see Q6 above). Combine it with concurrent tests and stress runs when the design shares memory.
Should I search “Go” or “Golang” interview questions?
Go is the language name; “Golang” is a common search term for it. The same slice, interface, and concurrency concepts apply to both queries.
Can I use an AI assistant during a live interview?
Only if your employer’s rules allow it. Assistants are useful for practice explanations beforehand. Using unauthorized help in a graded assessment can violate policy.
Continue preparing
For platform-style timed coding screens, see the HackerRank OA preparation guide and the CodeSignal OA guide. For choosing practice tools ethically before interview day, see best AI interview practice tools.
Official Go references
Continue preparing
Editor selected
HackerRank OA Preparation Guide 2026: Question Types, Practice Plan, and Tips
Prepare for a HackerRank OA in 2026 with current question types, coding and SQL patterns, a focused 7-day practice plan, timing tactics, and test-day tips.
Editor selected
Best AI Interview Practice Tools 2026: How to Choose and Use Them Ethically
Compare AI interview practice tools in 2026 and learn how to use them ethically for coding, behavioral, system design, and technical interview preparation.
Editor selected
CodeSignal OA Guide 2026: Score, Questions & Practice
Prepare for CodeSignal online assessments in 2026 with common question types, scoring expectations, coding patterns, and an ethical AI-assisted practice plan.
Same content type
Discord Software Engineer Interview Questions 2026: Real Coding, System Design & Process Guide
Prepare for Discord SWE interviews in 2026 with real-style coding questions, system design topics, behavioral prompts, interview process notes, and practical prep tips.
Ready to ace your next technical interview?
Join thousands of candidates who landed their dream jobs with SkillCopilotAI.

