shadow1ng/fscan · error

failed to create TXT file: %w

Error message

failed to create TXT file: %w

What it means

Wrap of an os.OpenFile failure in NewTXTWriter: the TXT output file at filePath could not be created/opened with the configured flags and permissions (common causes: a directory in the path does not exist, permission denied, or the path is invalid). The %w preserves the underlying OS error for errors.Is/As inspection.

Source

Thrown at common/output/writers.go:93

// TXTWriter - 文本格式写入器
// =============================================================================

// TXTWriter 文本格式写入器(分类缓冲,按类型聚合输出)
type TXTWriter struct {
	file         *os.File
	bufWriter    *bufio.Writer
	mu           sync.Mutex
	closed       bool
	buffer       *ResultBuffer // 内存分类缓冲
	realtimeFile *os.File      // 实时备份文件
	realtimePath string        // 实时备份文件路径
}

// NewTXTWriter 创建文本写入器
func NewTXTWriter(filePath string) (*TXTWriter, error) {
	file, err := os.OpenFile(filePath, DefaultFileFlags, DefaultFilePermissions)
	if err != nil {
		return nil, fmt.Errorf("failed to create TXT file: %w", err)
	}

	// 创建实时备份文件(防崩溃丢数据)
	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)
	}

	return &TXTWriter{
		file:         file,
		bufWriter:    bufio.NewWriter(file),
		buffer:       NewResultBuffer(),
		realtimeFile: realtimeFile,
		realtimePath: realtimePath,
	}, nil
}

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Check the wrapped error: if 'no such file or directory', create the parent directory first
  2. Fix permissions (chmod/chown or run with a user that can write the output path)
  3. Verify the path is a file location, not an existing directory, and that the path is valid on the OS

Example fix

// before
w, err := NewTXTWriter("/nonexistent/dir/out.txt")
// after
os.MkdirAll("/nonexistent/dir", 0o755)
w, err := NewTXTWriter("/nonexistent/dir/out.txt")
Defensive patterns

Strategy: validation

Validate before calling

if info, err := os.Stat(filepath.Dir(filePath)); err != nil || !info.IsDir() {
    os.MkdirAll(filepath.Dir(filePath), 0o755)
}
if info, err := os.Stat(filePath); err == nil && info.IsDir() {
    return errors.New("output path is a directory")
}

Try / catch

w, err := NewTXTWriter(path)
if err != nil {
    var pe *fs.PathError
    if errors.As(err, &pe) && errors.Is(pe.Err, fs.ErrPermission) {
        return fmt.Errorf("cannot write output %s: permission denied", path)
    }
    return err
}

Prevention

When it happens

Trigger: Output directory does not exist, permission denied on the path, path is a directory, disk full, or invalid characters in filePath on the target OS.

Common situations: Read-only output directory, missing parent directory (createOutputDir not run or wrong path), running under a service account without write access, SELinux/container volume restrictions.

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


AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06). Data as JSON: /api/errors/1d29b6f29157639c. Report an issue: GitHub.