junegunn/fzf · error
invalid history file: ${e.Error()}
Error message
invalid history file: ${e.Error()} What it means
Returned by startHttpServer (src/server.go:102) when net.Listen('unix', address.sock) fails while creating the listener for fzf's --listen UNIX socket mode. This happens after the stale-socket check, so the file was either absent or just removed; the operating system itself refused to bind a UNIX domain socket at that path. The underlying errno is unfortunately not wrapped into the message.
Source
Thrown at src/history.go:24
"strings"
)
// History struct represents input history
type History struct {
path string
lines []string
modified map[int]string
maxSize int
cursor int
}
// NewHistory returns the pointer to a new History struct
func NewHistory(path string, maxSize int) (*History, error) {
fmtError := func(e error) error {
if os.IsPermission(e) {
return errors.New("permission denied: " + path)
}
return errors.New("invalid history file: " + e.Error())
}
// Read history file
data, err := os.ReadFile(path)
if err != nil {
// If it doesn't exist, check if we can create a file with the name
if os.IsNotExist(err) {
data = []byte{}
if err := os.WriteFile(path, data, 0600); err != nil {
return nil, fmtError(err)
}
} else {
return nil, fmtError(err)
}
}
// Split lines and limit the maximum number of lines
lines := strings.Split(strings.Trim(string(data), "\n"), "\n")
if len(lines[len(lines)-1]) > 0 {View on GitHub (pinned to bd4efa277b)
Solutions
- Check that the socket's parent directory exists and is writable: `mkdir -p ~/.cache/fzf && [ -w ~/.cache/fzf ]`. Prefer $XDG_RUNTIME_DIR or $TMPDIR for socket paths.
- Shorten the socket path if it is near 104+ characters; use something like /tmp/fzf.sock.
- If the path is on NFS or a network/odd filesystem, move it to a local filesystem such as /tmp or /run/user/$(id -u).
- If a non-socket entry (e.g. a directory) has the socket's name, remove or rename it: `rm -rf /path/fzf.sock` only if it is yours.
- Re-run with strace (`strace -f -e trace=bind fzf --listen ...`) to capture the exact errno if the above does not resolve it.
Example fix
# before
fzf --listen /run/fzf/main-listener-socket.sock # /run not writable, path too long
# after
mkdir -p "${XDG_RUNTIME_DIR:-/tmp}/fzf"
fzf --listen "${XDG_RUNTIME_DIR:-/tmp}/fzf/fzf.sock" Defensive patterns
Strategy: validation
Validate before calling
// Go caller: verify the socket path is bindable before spawning fzf
func canBindUnixSocket(sockPath string) bool {
if len(sockPath) >= 104 { // typical sun_path limit
return false
}
dir := filepath.Dir(sockPath)
info, err := os.Stat(dir)
if err != nil || !info.IsDir() {
return false
}
// probe writability by creating and removing a temp file in dir
f, err := os.CreateTemp(dir, ".probe-*")
if err != nil {
return false
}
f.Close()
os.Remove(f.Name())
return true
} Type guard
func isUnixListenFailure(stderr string) bool {
return strings.Contains(stderr, "failed to listen on ") &&
strings.HasSuffix(strings.TrimSpace(strings.Split(stderr, "\n")[0]), ".sock")
} Try / catch
// shell wrapper: fail with diagnostics instead of a bare fzf error
if ! fzf --listen "$SOCK" 2>err.log; then
if grep -q "failed to listen on $SOCK" err.log; then
echo "cannot bind $SOCK: check dir exists/writable, path length < 104, local fs" >&2
fi
fi Prevention
- Default socket paths to $XDG_RUNTIME_DIR or $TMPDIR, never arbitrary absolute dirs.
- Keep socket paths short (< 104 bytes).
- Avoid placing sockets on NFS/FAT/overlay mounts.
When it happens
Trigger: Calling fzf --listen /some/dir/fzf.sock where the parent directory does not exist, is not writable by the current user, or the path crosses a filesystem that disallows sockets (e.g. some NFS mounts, /proc, FAT). Also triggered when the path is too long (UNIX socket paths are limited to ~104-108 bytes) or a non-socket file system entry occupies the name in a way os.Stat/os.Remove could not clear (e.g. a directory with that exact name).
Common situations: Pointing --listen at a socket path inside a directory the user cannot write (e.g. /run/fzf.sock as non-root); a socket path on an NFS/overlay mount that returns EOPNOTSUPP or EACCES; typos in the directory part of the socket path; paths generated with long temp prefixes exceeding sun_path limits; containers where the chosen directory is read-only.
Related errors
- permission denied: ${path}
- no directory specified
- invalid popup option: ${arg} (expected: [center|top|bottom|l
- not a valid integer: ${str}
- not a valid number: ${str}
AI-assisted analysis of junegunn/fzf@bd4efa277b (2026-08-15).
Data as JSON: /api/errors/e307786c393524c1.
Report an issue: GitHub.