shadow1ng/fscan · error

failed to create JSON file: %w

Error message

failed to create JSON file: %w

What it means

NewJSONWriter creates (truncating) the main output file and returns this error when os.OpenFile fails. Without the main JSON file the writer cannot be constructed, so the constructor aborts and returns the wrapped OS error.

Source

Thrown at common/output/writers.go:482

	Hosts    []*ScanResult `json:"hosts,omitempty"`
	Ports    []*ScanResult `json:"ports,omitempty"`
	Services []*ScanResult `json:"services,omitempty"`
	Vulns    []*ScanResult `json:"vulns,omitempty"`
}

// JSONSummary 扫描摘要
type JSONSummary struct {
	TotalHosts    int `json:"total_hosts"`
	TotalPorts    int `json:"total_ports"`
	TotalServices int `json:"total_services"`
	TotalVulns    int `json:"total_vulns"`
}

// NewJSONWriter 创建JSON写入器
func NewJSONWriter(filePath string) (*JSONWriter, 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 JSON file: %w", err)
	}

	// 创建实时备份文件(NDJSON格式,每行一个JSON对象)
	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 &JSONWriter{
		file:         file,
		buffer:       NewResultBuffer(),
		realtimeFile: realtimeFile,
		realtimePath: realtimePath,
	}, nil
}

View on GitHub (pinned to 95cc12e753)

Solutions

  1. os.MkdirAll(filepath.Dir(filePath), 0o755) before calling NewJSONWriter
  2. Verify filePath is a file path, not an existing directory
  3. Check write permissions for the process user on the target directory
  4. Inspect the wrapped error (ENOSPC/EACCES/ENOENT) for the specific cause
  5. Check ulimit -n if many files are open simultaneously

Example fix

// before
w, err := output.NewJSONWriter("./results/out.json")
// after
if err := os.MkdirAll(filepath.Dir("./results/out.json"), 0o755); err != nil {
	return err
}
w, err := output.NewJSONWriter("./results/out.json")
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("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.NewJSONWriter(path)
if err != nil {
	var pe *fs.PathError
	if errors.As(err, &pe) && errors.Is(pe.Err, syscall.ENOENT) {
		os.MkdirAll(filepath.Dir(path), 0o755)
		w, err = output.NewJSONWriter(path)
	}
	if err != nil { return err }
}

Prevention

When it happens

Trigger: os.OpenFile(filePath, O_CREATE|O_WRONLY|O_TRUNC) fails: nonexistent parent directory, no write permission, filePath is a directory, or too many open files.

Common situations: Config points to a directory path like ./out/ instead of a file; output directory never created before calling NewJSONWriter; running under a user lacking permission on the target dir; path contains invalid characters.

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/a3b470b5e9fe2a4d. Report an issue: GitHub.