shadow1ng/fscan · error
writer is closed
Error message
writer is closed
What it means
State guard in TXTWriter.Write: an attempt was made to write a scan result after the writer had already been closed (Close sets w.closed). Once closed the buffered file and realtime backup file are no longer valid for writes, so any further Write is rejected.
Source
Thrown at common/output/writers.go:124
bufWriter: bufio.NewWriter(file),
buffer: NewResultBuffer(),
realtimeFile: realtimeFile,
realtimePath: realtimePath,
}, nil
}
// WriteHeader 写入头部
func (w *TXTWriter) WriteHeader() error {
return nil
}
// Write 收集扫描结果到分类缓冲,同时实时备份
func (w *TXTWriter) Write(result *ScanResult) error {
w.mu.Lock()
defer w.mu.Unlock()
if w.closed {
return fmt.Errorf("writer is closed")
}
if result == nil {
return fmt.Errorf("result cannot be nil")
}
// 1. 加入内存分类缓冲(用于最终有序输出)
w.buffer.Add(result)
// 2. 实时写入备份文件(防崩溃丢数据)
if w.realtimeFile != nil {
line := w.formatLine(result)
if _, err := w.realtimeFile.WriteString(line + "\n"); err != nil {
return fmt.Errorf("failed to write realtime backup: %w", err)
}
if err := w.realtimeFile.Sync(); err != nil {
return fmt.Errorf("failed to sync realtime backup: %w", err)
}
}View on GitHub (pinned to 95cc12e753)
Solutions
- Stop all producers before closing the writer (use WaitGroup or done channel)
- Check writer lifecycle: create a new writer for a new run
- Reorder shutdown so Close is the last operation after all writes
Example fix
// before go writeResults(w); w.Close() // workers may write after close // after wg.Wait() // producers done w.Close()
Defensive patterns
Strategy: validation
Try / catch
if err := w.Write(res); err != nil {
if strings.Contains(err.Error(), "writer is closed") {
return errors.New("write after close: producer lifecycle bug")
}
return err
} Prevention
- Coordinate producer goroutines with WaitGroup before Close
- Create a fresh TXTWriter per run instead of resurrecting closed writers
- Make Close the final step in a single shutdown routine
When it happens
Trigger: Calling Write after TXTWriter.Close(); manager Close() cascading to writer close while workers still emit results; reusing a writer created via NewTXTWriter across runs.
Common situations: Producer goroutines outliving writer shutdown, double-close-then-write patterns, using the Manager after Flush/Close while writers are already closed.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- output manager is closed
- output config cannot be nil
- unsupported format: %s
- result cannot be nil
- failed to create TXT file: %w
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/770491c0a97454ad.
Report an issue: GitHub.