samber/cc-skills-golang/golang-safety
Claude Code and agent skill by samber/cc-skills-golang
- community
Checking that the SKILL.md file is still in the repository.
Defensive Golang coding against accidental bugs — nil panics, typed-nil interfaces, `append` backing-array aliasing, silent int64-to-int32 truncation, float `==` comparison, `defer` inside loops, defensive copies of slices and maps, and usable zero values. Use when a Go program panics on a nil map write or nil pointer dereference, when reviewing code for nil-safety, numeric conversion overflow, or resource lifecycle, or when designing a type whose zero value must be safe. Not for designing concurrent access with goroutines, channels, or sync primitives (→ See `samber/cc-skills-golang@golang-concurrency` skill), not for exploitable vulnerabilities such as injection, weak crypto, or leaked secrets (→ See `samber/cc-skills-golang@golang-security` skill), and not for debugging an already-failing program (→ See `samber/cc-skills-golang@golang-troubleshooting` skill).
Install
npx vskill@latest install samber/cc-skills-golang/golang-safetySKILL.md
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+ preferreflect.TypeAssert[T](value)overvalue.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 —
int64toint32wraps 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:
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 |
See [Nil Safety Deep Dive](./references/nil-safety.md) 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:
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](./references/slice-map-safety.md) for range pitfalls, subslice memory retention, and slices.Clone/maps.Clone.
Numeric Safety
Implicit type conversions truncate silently
Float comparison
Division by zero
Integer division by zero panics. Float division by zero produces +Inf, -Inf, or NaN.
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:
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
Initialization Safety
Zero-value design
Design types so var x MyType is safe — prevents "forgot to initialize" bugs:
sync.Once for lazy initialization
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).
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-concurrencyskill for concurrent access patterns and sync primitives - → See
samber/cc-skills-golang@golang-data-structuresskill for slice/map internals, capacity growth, and container/ packages - → See
samber/cc-skills-golang@golang-error-handlingskill for nil error interface trap - → See
samber/cc-skills-golang@golang-securityskill for security-relevant safety issues (memory safety, integer overflow) - → See
samber/cc-skills-golang@golang-troubleshootingskill for debugging panics and race conditions - → See
samber/cc-skills-golang@golang-continuous-integrationskill for automated AI-driven code review in CI using these guidelines
Security
- Security scanPassed, 85 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/golang-safety/SKILL.md
Popularity
- Repository stars
- 2,949
- Repository forks
- 192
- 7-day trend score
- 40
Stars and forks are for the whole GitHub repository, not this skill alone. Refreshed 25 Mar 2026, 7 months ago.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/samber/cc-skills-golang/golang-safety)