moonD4rk/HackBrowserData · error
copy: %w
Error message
copy: %w
What it means
Acquire wraps a copyFile failure with "copy: %w" when the platform is NOT Windows. On non-Windows systems there is no locked-file fallback, so any error from the plain file copy (open, read, or write failure) is surfaced under this prefix. On Windows this same prefix appears as one branch of a joined error when both the normal copy and the locked copy failed.
Source
Thrown at filemanager/session.go:49
// Acquire copies a browser file (or directory) from src to dst.
// For regular files, it also copies SQLite WAL and SHM companion files
// if they exist. For directories (e.g. LevelDB), it copies the entire
// directory while skipping lock files.
//
// On Windows, if the normal copy fails (e.g. file locked by Chrome),
// it falls back to DuplicateHandle + FileMapping to bypass exclusive locks.
func (s *Session) Acquire(src, dst string, isDir bool) error {
if isDir {
return copyDir(src, dst, "lock")
}
// Try normal copy first
err := copyFile(src, dst)
if err != nil {
// Only attempt locked-file fallback on Windows where Chrome holds exclusive locks.
// On other platforms, return the original error directly.
if runtime.GOOS != "windows" {
return fmt.Errorf("copy: %w", err)
}
if err2 := copyLocked(src, dst); err2 != nil {
return errors.Join(
fmt.Errorf("copy: %w", err),
fmt.Errorf("locked copy: %w", err2),
)
}
}
// Copy SQLite WAL/SHM companion files if present
var walErrs []error
for _, suffix := range []string{"-wal", "-shm"} {
walSrc := src + suffix
if isFileExists(walSrc) {
if err := copyFile(walSrc, dst+suffix); err != nil {
walErrs = append(walErrs, fmt.Errorf("copy %s: %w", suffix, err))
}
}View on GitHub (pinned to 0503d04d7a)
Solutions
- Verify the source file path exists and is readable by the current user (ls -l the profile directory).
- Ensure the destination (session temp dir) still exists and is writable — call session.Cleanup() only after extraction completes.
- Free disk space if the copy failed on write.
- On Windows, also read the joined "locked copy:" branch of the error to see why the fallback failed; restarting the browser or retrying often clears transient locks.
Example fix
// before
if err := s.Acquire(src, dst, false); err != nil {
log.Fatalf("acquire failed: %v", err)
}
// after
if err := s.Acquire(src, dst, false); err != nil {
if _, statErr := os.Stat(src); statErr != nil {
log.Warnf("source missing, skipping: %v", statErr)
return nil
}
return fmt.Errorf("acquire %s: %w", src, err)
} Defensive patterns
Strategy: validation
Validate before calling
// pre-check source readability and destination writability
if fi, err := os.Stat(src); err != nil || fi.IsDir() {
return fmt.Errorf("src %s not a readable file: %w", src, err)
}
if err := os.MkdirAll(filepath.Dir(dst), 0o700); err != nil {
return fmt.Errorf("dst dir: %w", err)
} Try / catch
// Go
if err := s.Acquire(src, dst, false); err != nil {
var pathErr *os.PathError
if errors.As(err, &pathErr) {
log.Warnf("filesystem error on %s: %v", pathErr.Path, pathErr.Err)
}
return err
} Prevention
- Verify profile paths for the installed browser version before extraction
- Run with read access to the target user's profile
- Keep disk space above a safe threshold
When it happens
Trigger: Session.Acquire(src, dst, false) on Linux/macOS where copyFile fails: source file missing, source unreadable (permissions), destination not writable, or destination directory missing. On Windows it also appears whenever copyLocked also fails, producing errors.Join of both errors.
Common situations: Browser profile path changed in a recent browser version; running without read access to another user's profile; disk full; the SQLite database deleted while the browser was updating; destination temp dir removed mid-run.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
AI-assisted analysis of moonD4rk/HackBrowserData@0503d04d7a (2026-09-06).
Data as JSON: /api/errors/29d1da2132d6069c.
Report an issue: GitHub.