shadow1ng/fscan · error
failed to create CSV file: %w
Error message
failed to create CSV file: %w
What it means
NewCSVWriter creates (truncating) the main CSV output file; this error is returned when os.OpenFile fails. The constructor aborts and returns the wrapped OS error, since a CSV writer cannot function without its output file.
Source
Thrown at common/output/writers.go:612
// CSVWriter CSV格式写入器(分类去重)
// 双写机制:内存分类缓冲 + 实时NDJSON备份
type CSVWriter struct {
file *os.File
bufWriter *bufio.Writer
csvWriter *csv.Writer
mu sync.Mutex
closed bool
buffer *ResultBuffer
realtimeFile *os.File // 实时备份文件(NDJSON格式)
realtimePath string // 实时备份文件路径
}
// NewCSVWriter 创建CSV写入器
func NewCSVWriter(filePath string) (*CSVWriter, error) {
file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, DefaultFilePermissions)
if err != nil {
return nil, fmt.Errorf("failed to create CSV file: %w", err)
}
// 创建实时备份文件(NDJSON格式)
realtimePath := filePath + ".realtime.tmp"
realtimeFile, err := os.OpenFile(realtimePath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, DefaultFilePermissions)
if err != nil {
file.Close()
return nil, fmt.Errorf("failed to create realtime backup file: %w", err)
}
bufWriter := bufio.NewWriter(file)
csvWriter := csv.NewWriter(bufWriter)
return &CSVWriter{
file: file,
bufWriter: bufWriter,
csvWriter: csvWriter,
buffer: NewResultBuffer(),View on GitHub (pinned to 95cc12e753)
Solutions
- Create the parent directory first with os.MkdirAll(filepath.Dir(filePath), 0o755)
- Verify filePath is a valid writable file path, not a directory
- Check filesystem permissions for the running user
- Inspect the wrapped error (ENOENT/EACCES/ENOSPC) for the specific cause
- Check ulimit -n if the process holds many open files
Example fix
// before
w, err := output.NewCSVWriter(cfg.OutputPath)
// after
if err := os.MkdirAll(filepath.Dir(cfg.OutputPath), 0o755); err != nil {
return err
}
w, err := output.NewCSVWriter(cfg.OutputPath) Defensive patterns
Strategy: validation
Validate before calling
if err := os.MkdirAll(filepath.Dir(filePath), 0o755); err != nil { return err }
if fi, err := os.Stat(filePath); err == nil && fi.IsDir() { return fmt.Errorf("CSV path is a directory: %s", filePath) }
probe, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil { return err }
probe.Close() Try / catch
w, err := output.NewCSVWriter(path)
if err != nil {
var pe *fs.PathError
if errors.As(err, &pe) {
if errors.Is(pe.Err, syscall.ENOENT) { os.MkdirAll(filepath.Dir(path), 0o755) }
if errors.Is(pe.Err, syscall.EACCES) { return fmt.Errorf("check permissions on %s", pe.Path) }
}
return err
} Prevention
- Create output directories at startup before constructing writers
- Validate CSV output paths in config (exists, writable, not a directory)
- Run under a user with write access to the output location
- Pre-flight probe writes before starting long scans
- Monitor fd usage to stay under the open-file limit
When it happens
Trigger: os.OpenFile(filePath, O_CREATE|O_WRONLY|O_TRUNC) fails: parent directory missing, no write permission, filePath is an existing directory, or fd limit exhausted.
Common situations: Output path configured as a directory or pointing at a nonexistent folder; running as a user without permission on the output directory; path typos; read-only container volume.
Understand the failure class
Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.
Related errors
- failed to create JSON file: %w
- failed to write realtime backup: %w
- failed to sync realtime backup: %w
- webscan_cel_env_not_initialized
- no transport
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/3b95fe204d591ad4.
Report an issue: GitHub.