cilium/cilium · error

wal closed

Error message

wal closed

What it means

Writer.Write returns "wal closed" when the WAL's underlying log file is nil, meaning the WAL has been closed (or never initialized) and can no longer accept appends. It guards against writing to a closed file handle after Close or a failed open. Writes are rejected immediately instead of panicking on a nil resource.

Source

Thrown at pkg/wal/wal.go:113

func (be BatchErrors) Error() string {
	var builder strings.Builder
	for i, e := range be {
		if i > 0 {
			builder.WriteString("; ")
		}
		builder.WriteString(e.Error())
	}
	return builder.String()
}

// Write appends an event to the WAL. Data is flushed to disk before returning.
func (w *Writer[T]) Write(e ...T) error {
	w.mu.Lock()
	defer w.mu.Unlock()

	if w.log == nil {
		return fmt.Errorf("wal closed")
	}

	var ba BatchErrors
	for i, e := range e {
		data, err := e.MarshalBinary()
		if err != nil {
			ba = append(ba, BatchError{Index: i, Err: err})
			continue
		}

		lv := &lvWriter{w: w.log}
		if err := lv.Write(data); err != nil {
			ba = append(ba, BatchError{Index: i, Err: err})
			continue
		}
	}

	// Ensure the data is flushed to disk.

View on GitHub (pinned to ac7b90affa)

Solutions

  1. Ensure Close() is called only after all producer goroutines have stopped writing (use WaitGroup/context cancellation).
  2. Re-create or re-open the WAL writer before writing again after a Close.
  3. Check application startup logs for a failed WAL open that left the writer uninitialized.
  4. Serialize writes through a single owner so no code path writes after shutdown begins.

Example fix

// before
wal.Close()
wal.Write(evt) // "wal closed"
// after
wal.Write(evt)
wal.Close() // close only after final write
Defensive patterns

Strategy: try-catch

Validate before calling

// Go: guard before writing
if wal == nil || wal.Closed() {
    return errors.New("wal writer is closed")
}

Try / catch

if err := wal.Write(evt); err != nil {
    if strings.Contains(err.Error(), "wal closed") {
        // stop producers / reopen wal
    }
    return err
}

Prevention

When it happens

Trigger: Calling Write(e...) on a *Writer[T] whose log field is nil — i.e. after Close() was called, or the writer was constructed/initialized without successfully opening the log file.

Common situations: Shutdown ordering bugs where a producer goroutine keeps appending after the WAL was closed during teardown; reusing a writer across restarts without re-creating it; a failed Open/Init leaving a writer with a nil log.

Related errors


AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31). Data as JSON: /api/errors/6cef63933b5ee16d. Report an issue: GitHub.