moonD4rk/HackBrowserData · error
write %s: %w
Error message
write %s: %w
What it means
This error wraps an OS-level failure that occurred while writing the formatted browser data buffer to an output file (e.g. password.csv, cookie.json) via f.Write(buf.Bytes()) in writeFile. The library opens the destination file itself and streams the aggregated rows to it; if the underlying write syscall fails (disk full, I/O error, file closed/invalid handle), the original error is wrapped with the target filename as context. It is distinct from the earlier 'create %s' error (which fires at os.OpenFile) and the 'write BOM' error (which fires only for CSV BOM bytes).
Source
Thrown at output/output.go:165
f, err := os.OpenFile(filepath.Clean(path), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o600)
if err != nil {
return fmt.Errorf("create %s: %w", filename, err)
}
defer func() {
if cerr := f.Close(); cerr != nil && err == nil {
err = fmt.Errorf("close %s: %w", filename, cerr)
}
}()
if strings.HasSuffix(path, ".csv") {
if _, err := f.Write(utf8BOM); err != nil {
return fmt.Errorf("write BOM: %w", err)
}
}
if _, err := f.Write(buf.Bytes()); err != nil {
return fmt.Errorf("write %s: %w", filename, err)
}
return nil
}
View on GitHub (pinned to 0503d04d7a)
Solutions
- Check free disk space on the output directory's filesystem (df -h <outdir>) and free space or redirect output to another disk with a larger capacity.
- Verify the output directory is not on a read-only or failing filesystem: check `mount` for 'ro' flags or dmesg for I/O errors; move -o/--output to a healthy local path.
- Check for disk quotas (quota -s or cloud-provider limits) and raise them or reduce output volume.
- Rerun the command; transient I/O errors on network mounts may succeed on retry after the mount recovers.
- If it persists, inspect the wrapped inner error (%w) in the message — it names the exact syscall errno — and address that specific cause (e.g. EDQUOT, ENOSPC, EIO).
Example fix
// before: letting Write fail mid-export with a raw wrapped OS error
if err := w.Write(); err != nil {
log.Fatal(err) // "write password.csv: ... no space left on device"
}
// after: preflight disk space and fall back to an alternate output dir
func ensureSpace(dir string, needBytes int64) error {
var st syscall.Statfs_t
if err := syscall.Statfs(dir, &st); err != nil {
return err
}
if int64(st.Bavail)*int64(st.Bsize) < needBytes {
return fmt.Errorf("insufficient space in %s", dir)
}
return nil
}
if err := ensureSpace(outDir, 10<<20); err != nil {
outDir = filepath.Join(os.TempDir(), "hbd-export") // fallback location
}
w, _ := output.NewWriter(outDir, "csv") Defensive patterns
Strategy: try-catch
Validate before calling
// Go has no try/catch; validate writable destination before calling Write()
func dirIsWritable(dir string) error {
if st, err := os.Stat(dir); err != nil || !st.IsDir() {
return fmt.Errorf("not a directory: %s", dir)
}
probe := filepath.Join(dir, ".hbd-write-probe")
f, err := os.OpenFile(probe, os.O_CREATE|os.O_WRONLY, 0o600)
if err != nil {
return err
}
if _, err := f.WriteString("x"); err != nil { // catches full/read-only FS at write stage
f.Close()
os.Remove(probe)
return err
}
f.Close()
os.Remove(probe)
return nil
}
if err := dirIsWritable(outDir); err != nil {
log.Fatalf("output dir not writable: %v", err)
} Type guard
// Ensure the Writer was constructed with a valid, existing directory before Write()
func validWriter(w *output.Writer, dir string) bool {
st, err := os.Stat(dir)
return w != nil && err == nil && st.IsDir()
} Try / catch
// Go: inspect the wrapped error and classify the errno
if err := w.Write(); err != nil {
var pe *os.PathError
if errors.As(err, &pe) {
switch {
case errors.Is(pe.Err, syscall.ENOSPC):
log.Fatalf("disk full: free space on %s and retry", outDir)
case errors.Is(pe.Err, syscall.EACCES), errors.Is(pe.Err, syscall.EROFS):
log.Fatalf("cannot write %s: check permissions/read-only mount", pe.Path)
default:
log.Fatalf("export failed: %v", err)
}
}
log.Fatalf("export failed: %v", err)
} Prevention
- Pre-check free disk space on the target filesystem before running an export that may produce large history/download dumps.
- Choose an output directory on a reliable local filesystem rather than network or removable mounts.
- Run with a user account that owns or has write access to the output directory (avoid permission surprises from sudo-created dirs).
- Monitor dmesg/system logs for filesystem errors if exports repeatedly fail on the same host.
- Keep the wrapped error (%w) in logs — the inner errno (ENOSPC, EIO, EDQUOT) pinpoints the root cause faster than the filename alone.
When it happens
Trigger: Writer.Write() -> writeFile(category, rows): os.OpenFile succeeds but f.Write(buf.Bytes()) fails. Typical causes: disk full (ENOSPC), I/O error on the device (EIO), file opened on a read-only mount after creation succeeded via quirks, quota exceeded, or (rarely) a bad file descriptor if the deferred Close raced — though in this code the write happens before close, so it's almost always an OS/storage-level write failure. Not triggered by formatting errors (those return 'format %s') or empty buffers (no file is created).
Common situations: Running the tool against a full or nearly-full disk (common on small VPS or live-USB environments). Output directory on a failing/removable USB drive or network mount (SMB/NFS) that drops mid-write. Disk quota exceeded on shared hosting or university lab machines. Filesystem went read-only after a kernel detected errors (ext4 remount-ro). SELinux/AppArmor policies that allow file creation but block writes in certain contexts.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
AI-assisted analysis of moonD4rk/HackBrowserData@0503d04d7a (2026-09-06).
Data as JSON: /api/errors/7aed3b759f27c580.
Report an issue: GitHub.