moonD4rk/HackBrowserData · error

create output dir: %w

Error message

create output dir: %w

What it means

Writer.Write creates the output directory (os.MkdirAll, mode 0750) before writing per-category files like password.csv. This error wraps the MkdirAll failure, meaning no output could be written because the destination directory could not be created (or, for an existing path, is not a directory).

Source

Thrown at output/output.go:61

	if err != nil {
		return nil, err
	}
	return &Writer{dir: dir, formatter: f}, nil
}

// Add accumulates one browser profile's data for later writing.
func (o *Writer) Add(browser, profile string, data *types.BrowserData) {
	if data == nil {
		return
	}
	o.results = append(o.results, result{browser, profile, data})
}

// Write aggregates all accumulated data by category and writes each
// non-empty category to its own file (e.g. password.csv, cookie.json).
func (o *Writer) Write() error {
	if err := os.MkdirAll(o.dir, 0o750); err != nil {
		return fmt.Errorf("create output dir: %w", err)
	}
	agg := o.aggregate()
	for _, cs := range agg {
		if err := o.writeFile(cs.name, cs.rows); err != nil {
			return err
		}
	}
	if len(agg) > 0 {
		fmt.Fprintln(os.Stderr)
		log.Infof("Exported to %s/", o.dir)
		for _, cs := range agg {
			filename := fmt.Sprintf("%s.%s", cs.name, o.formatter.ext())
			log.Infof("  %-24s %d entries", filename, len(cs.rows))
		}
	}
	return nil
}

View on GitHub (pinned to 0503d04d7a)

Solutions

  1. Choose a writable output directory (e.g. project dir or user temp) and pass that to NewWriter.
  2. Check whether a file occupies the output path and remove/rename it.
  3. Verify permissions on the parent directory (write + execute bits) and free disk space.
  4. Run the process with sufficient privileges or use os.Getwd()/os.UserCacheDir() as a fallback location.

Example fix

// before: fixed system path may not be writable
w, _ := output.NewWriter("/var/secure-out", "csv", nil)
// after: fall back to a writable dir
if _, err := os.Stat("/var/secure-out"); err != nil {
	dir, _ = os.MkdirTemp("", "hbd-out")
}
w, _ := output.NewWriter(dir, "csv", nil)
Defensive patterns

Strategy: try-catch

Validate before calling

if fi, err := os.Stat(dir); err == nil && !fi.IsDir() {
	return fmt.Errorf("output path %s is a file", dir)
}
probe := filepath.Join(dir, ".probe")
if err := os.WriteFile(probe, nil, 0o600); err != nil {
	return fmt.Errorf("output dir not writable: %w", err)
}
os.Remove(probe)

Type guard

func isWritableDir(path string) bool {
	fi, err := os.Stat(path)
	return err == nil && fi.IsDir() || os.IsNotExist(err)
}

Try / catch

if err := w.Write(); err != nil {
	var pe *fs.PathError
	if errors.As(err, &pe) && strings.Contains(err.Error(), "create output dir") {
		// switch to fallback dir and retry
	}
}

Prevention

When it happens

Trigger: os.MkdirAll(o.dir, 0o750) failed: parent directories missing/unwritable, disk full, the target path exists as a regular file, or the process lacks permission at that location.

Common situations: Output dir set to a read-only location or another user's home; a file already exists at the output path; running on a read-only mounted volume or full disk; invalid path characters/overly long paths on Windows; sandboxed/CI environments restricting writes.

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


AI-assisted analysis of moonD4rk/HackBrowserData@0503d04d7a (2026-09-06). Data as JSON: /api/errors/fc7b57621c8ea9fd. Report an issue: GitHub.