# panic: runtime error: close of nil channel

- **ID:** `go/panic-runtime-error-close-of-nil-channel`
- **Domain:** go
- **Category:** runtime_error
- **Verification:** ai_generated
- **Fix Rate:** 95%

## Root Cause

Attempting to close a channel variable that has not been initialized (nil) using close(ch).

## Version Compatibility

| Version | Status | Introduced | Deprecated |
|---------|--------|------------|------------|
| go1.20 | active | — | — |
| go1.21 | active | — | — |
| go1.22 | active | — | — |

## Workarounds

1. **Initialize the channel with make() before using: ch := make(chan T); defer close(ch)** (95% success)
   ```
   Initialize the channel with make() before using: ch := make(chan T); defer close(ch)
   ```
2. **Guard close with a nil check: if ch != nil { close(ch) } else { /* handle nil case */ }** (93% success)
   ```
   Guard close with a nil check: if ch != nil { close(ch) } else { /* handle nil case */ }
   ```
3. **Use sync.Once to ensure close is called only once and after initialization: var closeOnce sync.Once; closeOnce.Do(func() { close(ch) })** (90% success)
   ```
   Use sync.Once to ensure close is called only once and after initialization: var closeOnce sync.Once; closeOnce.Do(func() { close(ch) })
   ```

## Dead Ends

- **Wrap close(ch) in a recover() block to catch the panic** — Recovering doesn't fix the root cause and may mask a logic error (70% fail)
- **Use select with default to check if channel is nil before closing** — select doesn't detect nil channels at compile time; it's a runtime check that still panics if nil (80% fail)
- **Set ch = make(chan T) before every close call** — Overwrites the existing channel and may cause goroutine leaks or lost messages (60% fail)
