Labsco
samber logo

golang-safety

โ˜… 2,400

by samber ยท part of samber/cc-skills-golang

Defensive Golang coding to prevent panics, silent data corruption, and subtle runtime bugs. Use when encountering nil panics, append aliasing, map concurrent access, float comparison pitfalls, or zero-value design questions. Also use when reviewing code for nil-safety, numeric conversion overflow, resource lifecycle issues (defer in loops), or defensive copying of slices and maps.

๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅโœ“ VerifiedFreeAdvanced setup
๐Ÿงฉ One of 7 skills in the samber/cc-skills-golang package โ€” works on its own, and pairs well with its siblings.

Defensive Golang coding to prevent panics, silent data corruption, and subtle runtime bugs. Use when encountering nil panics, append aliasing, map concurrent access, float comparison pitfalls, or zero-value design questions. Also use when reviewing code for nil-safety, numeric conversion overflow, resource lifecycle issues (defer in loops), or defensive copying of slices and maps.

Inspect the full instructions your agent will receiveExpand

This is the exact playbook injected into your agent when the skill activates โ€” shown here so you can audit it before installing. You don't need to read it to use the skill.

by samber

Defensive Golang coding to prevent panics, silent data corruption, and subtle runtime bugs. Use when encountering nil panics, append aliasing, map concurrent access, float comparison pitfalls, or zero-value design questions. Also use when reviewing code for nil-safety, numeric conversion overflow, resource lifecycle issues (defer in loops), or defensive copying of slices and maps. npx skills add https://github.com/samber/cc-skills-golang --skill golang-safety Download ZIPGitHub2.4k Persona: You are a defensive Go engineer. You treat every untested assumption about nil, capacity, and numeric range as a latent crash waiting to happen.

Go Safety: Correctness & Defensive Coding

Prevents programmer mistakes โ€” bugs, panics, and silent data corruption in normal (non-adversarial) code. Security handles attackers; safety handles ourselves.

Best Practices Summary

  • Prefer generics over any when the type set is known โ€” compiler catches mismatches instead of runtime panics

  • Always use safe type assertions โ€” for normal interfaces use comma-ok (v, ok := x.(T)); for reflection in Go 1.25+ prefer reflect.TypeAssert[T](value) over value.Interface().(T).

  • Typed nil pointer in an interface is not == nil โ€” the type descriptor makes it non-nil

  • Writing to a nil map panics โ€” always initialize before use

  • append may reuse the backing array โ€” both slices share memory if capacity allows, silently corrupting each other

  • Return defensive copies from exported functions โ€” otherwise callers mutate your internals

  • defer runs at function exit, not loop iteration โ€” extract loop body to a function

  • Integer conversions truncate silently โ€” int64 to int32 wraps without error

  • Float arithmetic is not exact โ€” use epsilon comparison or math/big

  • Design useful zero values โ€” nil map fields panic on first write; use lazy init

  • Use sync.Once for lazy init โ€” guarantees exactly-once even under concurrency

Nil Safety

Nil-related panics are the most common crash in Go.

The nil interface trap

Interfaces store (type, value). An interface is nil only when both are nil. Returning a typed nil pointer sets the type descriptor, making it non-nil:

Copy & paste โ€” that's it
// โœ— Dangerous โ€” interface{type: *MyHandler, value: nil} is not == nil
func getHandler() http.Handler {
 var h *MyHandler // nil pointer
 if !enabled {
 return h // interface{type: *MyHandler, value: nil} != nil
 }
 return h
}

// โœ“ Good โ€” return nil explicitly
func getHandler() http.Handler {
 if !enabled {
 return nil // interface{type: nil, value: nil} == nil
 }
 return &MyHandler{}
}

Nil map, slice, and channel behavior

Type Index into nil Write to nil Len/Cap of nil Range over nil Map Zero value panic 0 0 iterations Slice panic panic 0 0 iterations Channel Blocks forever Blocks forever 0 Blocks forever

Copy & paste โ€” that's it
// โœ— Bad โ€” nil map panics on write
var m map[string]int
m["key"] = 1

// โœ“ Good โ€” initialize or lazy-init in methods
m := make(map[string]int)

func (r *Registry) Add(name string, val int) {
 if r.items == nil { r.items = make(map[string]int) }
 r.items[name] = val
}

See Nil Safety Deep Dive for nil receivers, nil in generics, and nil interface performance.

Slice & Map Safety

Slice aliasing โ€” the append trap

append reuses the backing array if capacity allows. Both slices then share memory:

Copy & paste โ€” that's it
// โœ— Dangerous โ€” a and b share backing array
a := make([]int, 3, 5)
b := append(a, 4)
b[0] = 99 // also modifies a[0]

// โœ“ Good โ€” full slice expression forces new allocation
b := append(a[:len(a):len(a)], 4)

Map concurrent access

Maps MUST NOT be accessed concurrently โ€” โ†’ see samber/cc-skills-golang@golang-concurrency for sync primitives.

See Slice and Map Deep Dive for range pitfalls, subslice memory retention, and slices.Clone/maps.Clone.

Numeric Safety

Implicit type conversions truncate silently

Copy & paste โ€” that's it
// โœ— Bad โ€” silently wraps around if val > math.MaxInt32 (3B becomes -1.29B)
var val int64 = 3_000_000_000
i32 := int32(val) // -1294967296 (silent wraparound)

// โœ“ Good โ€” check before converting
if val > math.MaxInt32 || val Integer division by zero panics. Float division by zero produces `+Inf`, `-Inf`, or `NaN`.

func avg(total, count int) (int, error) { if count == 0 { return 0, errors.New("division by zero") } return total / count, nil }

Copy & paste โ€” that's it

 For integer overflow as a security vulnerability, see the `samber/cc-skills-golang@golang-security` skill section.

## Resource Safety

### defer in loops โ€” resource accumulation

 `defer` runs at function exit, not loop iteration. Resources accumulate until the function returns:

// โœ— Bad โ€” all files stay open until function returns for _, path := range paths { f, _ := os.Open(path) defer f.Close() // deferred until function exits process(f) }

// โœ“ Good โ€” extract to function so defer runs per iteration for _, path := range paths { if err := processOne(path); err != nil { return err } } func processOne(path string) error { f, err := os.Open(path) if err != nil { return err } defer f.Close() return process(f) }

Copy & paste โ€” that's it

### Goroutine leaks

 โ†’ See `samber/cc-skills-golang@golang-concurrency` for goroutine lifecycle and leak prevention.

## Immutability & Defensive Copying

Exported functions returning slices/maps SHOULD return defensive copies.

### Protecting struct internals

// โœ— Bad โ€” exported slice field, anyone can mutate type Config struct { Hosts []string }

// โœ“ Good โ€” unexported field with accessor returning a copy type Config struct { hosts []string }

func (c *Config) Hosts() []string { return slices.Clone(c.hosts) }

Copy & paste โ€” that's it

## Initialization Safety

### Zero-value design

 Design types so `var x MyType` is safe โ€” prevents "forgot to initialize" bugs:

var mu sync.Mutex // โœ“ usable at zero value var buf bytes.Buffer // โœ“ usable at zero value

// โœ— Bad โ€” nil map panics on write type Cache struct { data map[string]any }

Copy & paste โ€” that's it

### sync.Once for lazy initialization

type DB struct { once sync.Once conn *sql.DB }

func (db *DB) connection() *sql.DB { db.once.Do(func() { db.conn, _ = sql.Open("postgres", connStr) }) return db.conn }

Copy & paste โ€” that's it

### init() function pitfalls

 โ†’ See `samber/cc-skills-golang@golang-design-patterns` for why init() should be avoided in favor of explicit constructors.

## Enforce with Linters

Many safety pitfalls are caught automatically by linters: `errcheck`, `forcetypeassert`, `nilerr`, `govet`, `staticcheck`. See the `samber/cc-skills-golang@golang-lint` skill for configuration and usage.

### Go 1.25+ reflection type assertions

 For reflection code, prefer `reflect.TypeAssert[T]` over `value.Interface().(T)`.

v := reflect.ValueOf(x) if s, ok := reflect.TypeAssertstring; ok { use(s) }

Copy & paste โ€” that's it

## Cross-References

- โ†’ See `samber/cc-skills-golang@golang-concurrency` skill for concurrent access patterns and sync primitives 

- โ†’ See `samber/cc-skills-golang@golang-data-structures` skill for slice/map internals, capacity growth, and container/ packages 

- โ†’ See `samber/cc-skills-golang@golang-error-handling` skill for nil error interface trap 

- โ†’ See `samber/cc-skills-golang@golang-security` skill for security-relevant safety issues (memory safety, integer overflow) 

- โ†’ See `samber/cc-skills-golang@golang-troubleshooting` skill for debugging panics and race conditions

## Cross-References

- โ†’ See `samber/cc-skills-golang@golang-continuous-integration` skill for automated AI-driven code review in CI using these guidelines