Security is about attackers; this is about the mistakes we make ourselves — the nil value that panics, the slice quietly sharing memory with another, the number that loses its top half.
WHEN TO USE
SCOPE
USE FOR
Fix a Go program that panics on a nil map write or nil pointer dereference.
Review Go code for nil-safety, numeric overflow, or resource lifecycle bugs.
Design a struct whose zero value is safe to use without a constructor.
Catch an append call that silently aliases another slice's backing array.
Guard an int64-to-int32 conversion or a float equality check from silent bugs.
NOT FOR
Designing concurrent access with goroutines, channels, or sync primitives.
Exploitable vulnerabilities such as injection, weak crypto, or leaked secrets.
Debugging a program that is already failing in production.
This is a saved copy of the skill's SKILL.md instructions. It may differ from the upstream file or the version you install.
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:
// ✗ 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
// ✗ 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:
// ✗ 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
// ✗ 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 < math.MinInt32 {
return fmt.Errorf("value %d overflows int32", val)
}
i32 := int32(val)
Float comparison
// ✗ Bad — floating point arithmetic is not exact
var a, b, c float64 = 0.1, 0.2, 0.3
a+b == c // false
// ✓ Good — use epsilon comparison
const epsilon = 1e-9
math.Abs((a+b)-c) < epsilon // true
Division by zero
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
}
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)
}
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)
}
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 }
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
}
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.TypeAssert[string](v); ok {
use(s)
}
Common Mistakes
Mistake
Fix
Bare type assertion v := x.(T)
Panics on type mismatch, crashing the program. Use v, ok := x.(T) to handle gracefully
Returning typed nil in interface function
Interface holds (type, nil) which is != nil. Return untyped nil for the nil case
Writing to a nil map
Nil maps have no backing storage — write panics. Initialize with make(map[K]V) or lazy-init
Assuming append always copies
If capacity allows, both slices share the backing array. Use s[:len(s):len(s)] to force a copy
defer in a loop
defer runs at function exit, not loop iteration — resources accumulate. Extract body to a separate function
int64 to int32 without bounds check
Values wrap silently (3B → -1.29B). Check against math.MaxInt32/math.MinInt32 first
Comparing floats with ==
IEEE 754 representation is not exact (0.1+0.2 != 0.3). Use math.Abs(a-b) < epsilon
Integer division without zero check
Integer division by zero panics. Guard with if divisor == 0 before dividing
Returning internal slice/map reference
Callers can mutate your struct's internals through the shared backing array. Return a defensive copy
Multiple init() with ordering assumptions
init() execution order across files is unspecified. → See samber/cc-skills-golang@golang-design-patterns — use explicit constructors
Blocking forever on nil channel
Nil channels block on both send and receive. Always initialize before use
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
→ See samber/cc-skills-golang@golang-continuous-integration skill for automated AI-driven code review in CI using these guidelines
No requirements beyond installing this skill were found.
Listed as free
Connected services may require an account or charge fees.
Setup details
The README mentions source builds, cloning, containers, hosting, OAuth, service accounts, or cloud projects.
Run this outside your AI tool, using Node.js 22.20.0 or newer. Skills CLI 1.7.2 skips skill selection; prompts cancel installation without an interactive terminal. If choosing Project when asked about installation scope, open your project's folder before running this.
Install checklist
Check selected tools if a picker appears; Claude Code may be unchecked under Additional agents. ↑/↓ moves, Space toggles selections, Enter confirms.
Without a tool picker, check Installing to: for your intended tool. Stop if it names a different tool.
If asked, choose Symlink (Recommended) for shared files or Copy to all agents for separate copies; review the summary before confirming installation.
Install the find-skills skill? defaults to Yes, adding another skill for all projects. Choose No if you don't want that extra installation.
Skills CLI 1.7.2 sends install data to skills.sh by default, including the source, skill names, target tools and file details; GitHub sources are reported only when GitHub confirms the repository is public, while other remote sources can also be reported. Confirmed-public GitHub sources also trigger a security-audit request. Before installing, set the environment variable DO_NOT_TRACK=1 or DISABLE_TELEMETRY=1 to disable both.
After installing for Claude Code, open it in the installation project if you chose Project; Global makes the skill available across projects on this computer. Once Claude Code loads the skill, its description helps Claude decide when to use it.
If installation created a top-level skills folder that did not exist when your Claude Code session started, run /reload-skills in that session. Run it again after later changes in that folder.
Install the whole plugin
This route installs the Samber Golang Skills plugin package selected for your AI tool.
Add Samuel's marketplace, then install the plugin
Type both lines inside a Claude Code session, not at your shell prompt. The marketplace is a separate repository of Samuel Berthe's, samber/cc, which also lists his other plugins. The second line opens the details of cc-skills-golang, which carries this repository's 46 Go skills; pick one of the install options shown and Claude Code installs it.
01
/plugin marketplace add samber/cc
02
/plugin install cc-skills-golang@samber
Run it in your terminal. It copies the whole repository, with its 46 skills, into ~/.openclaw/skills/cc-skills-golang, OpenClaw's skills folder in your home folder. To install it for one OpenClaw workspace instead, Samuel gives ~/.openclaw/workspace/skills/cc-skills-golang as the folder.
Run it in your terminal, not inside Gemini CLI; installing from GitHub needs git on your computer. It installs the repository, with its 46 skills, as a Gemini CLI extension. To update it later, run gemini extensions update cc-skills-golang.
Run it in your terminal. It copies the whole repository, with its 46 skills, into ~/.cursor/skills/cc-skills-golang, Cursor's skills folder in your home folder.
Type it in an interactive GitHub Copilot CLI session, not at your shell prompt. It installs the repository straight from GitHub as a plugin, with its 46 skills and no marketplace to add first.
Golang benchmarking, profiling, and performance measurement. Use when writing, running, or comparing Go benchmarks, profiling hot paths with pprof, interpreting CPU/memory/trace profiles, analyzing results with benchstat, setting up CI benchmark regression detection, or investigating production performance with Prometheus runtime metrics. Also use when the developer needs deep analysis on a specific performance indicator - this skill provides the measurement methodology, while samber/cc-skills-golang@golang-performance provides the optimization patterns.Read full description
Golang CLI application development. Use when building, modifying, or reviewing a Go CLI tool — especially for command structure, flag handling, configuration layering, version embedding, exit codes, I/O patterns, signal handling, shell completion, argument validation, and CLI unit testing. Also triggers when code uses cobra, viper, or urfave/cli. For cobra-specific APIs → See samber/cc-skills-golang@golang-spf13-cobra skill; for viper configuration layering → See samber/cc-skills-golang@golang-spf13-viper skill.Read full description
Golang code style conventions — line length and breaking, variable declarations, control flow clarity, when comments help vs hurt. Use when writing or reviewing Go code, asking about style or clarity, or establishing project coding standards. Not for naming conventions (→ See samber/cc-skills-golang@golang-naming skill), linter configuration (→ See samber/cc-skills-golang@golang-lint skill), or doc comments (→ See samber/cc-skills-golang@golang-documentation skill).Read full description
Golang concurrency patterns. Use when writing or reviewing concurrent Go code involving goroutines, channels, select, locks, sync primitives, errgroup, singleflight, worker pools, or fan-out/fan-in pipelines. Also triggers when you detect goroutine leaks, race conditions, channel ownership issues, or need to choose between channels and mutexes.Read full description
Idiomatic context.Context usage in Golang — propagation through API boundaries, cancellation, timeouts and deadlines, request-scoped values, context.WithoutCancel for background work outliving requests. Apply when designing context propagation across layers, debugging leaked or unexpired contexts, choosing between context.Background/TODO/WithoutCancel, or storing values in context. Not for code that merely accepts ctx as first parameter.Read full description
CI/CD pipeline configuration using GitHub Actions for Golang projects — testing, linting, SAST, security scanning, code coverage, Dependabot, Renovate, GoReleaser, code review automation, and release pipelines. Use when setting up or improving Go project CI, configuring GitHub Actions workflows, adding linters or security scanners, automating dependency updates, or adding quality gates.Read full description