junegunn/fzf · error

FZF_API_KEY is required to allow remote access

Error message

FZF_API_KEY is required to allow remote access

What it means

fzf's HTTP server (--listen) was given a non-local bind address, but no FZF_API_KEY environment variable is set. Because a remote listener lets any reachable client drive the selector, fzf refuses to start without an API key. This is a deliberate security guard, not a misconfiguration of the address itself.

Source

Thrown at src/server.go:86

		return defaultListenAddr, fmt.Errorf("invalid listen address: %s", address)
	}
	portStr := parts[len(parts)-1]
	port, err := strconv.Atoi(portStr)
	if err != nil || port < 0 || port > 65535 {
		return defaultListenAddr, fmt.Errorf("invalid listen port: %s", portStr)
	}
	if len(parts[0]) == 0 {
		parts[0] = "localhost"
	}
	return listenAddress{parts[0], port, ""}, nil
}

func startHttpServer(address listenAddress, actionChannel chan []*action, getHandler func(getParams) string) (net.Listener, int, error) {
	host := address.host
	port := address.port
	apiKey := os.Getenv("FZF_API_KEY")
	if !address.IsLocal() && len(apiKey) == 0 {
		return nil, port, errors.New("FZF_API_KEY is required to allow remote access")
	}

	var listener net.Listener
	var err error
	if len(address.sock) > 0 {
		if _, err := os.Stat(address.sock); err == nil {
			// Check if the socket is already in use
			if conn, err := net.Dial("unix", address.sock); err == nil {
				conn.Close()
				return nil, 0, fmt.Errorf("socket already in use: %s", address.sock)
			}
			os.Remove(address.sock)
		}
		listener, err = net.Listen("unix", address.sock)
		if err != nil {
			return nil, 0, fmt.Errorf("failed to listen on %s", address.sock)
		}
		os.Chmod(address.sock, 0600)

View on GitHub (pinned to bd4efa277b)

Solutions

  1. Set an API key: export FZF_API_KEY=$(head -c16 /dev/urandom | base64) before starting fzf
  2. Or restrict the listener to loopback if remote access is not actually needed: --listen=127.0.0.0:6266 or plain --listen
  3. Clients must then send the key via the X-api-key header on every request

Example fix

# before
fzf --listen=0.0.0.0:6266
# after
export FZF_API_KEY='s3cret-key'
fzf --listen=0.0.0.0:6266
curl -H 'X-api-key: s3cret-key' http://host:6266/?q=query
Defensive patterns

Strategy: validation

Validate before calling

# guard the listener start in shell
host=0.0.0.0; port=6266
if [ "$host" != "localhost" ] && [ "$host" != "127.0.0.1" ] && [ -z "${FZF_API_KEY:-}" ]; then
  echo 'refusing remote --listen without FZF_API_KEY' >&2; exit 1
fi
fzf --listen="$host:$port"

Prevention

When it happens

Trigger: Running e.g. fzf --listen=0.0.0.0:6266 or --listen=192.168.1.5:6266 without FZF_API_KEY in the environment; only loopback hosts (localhost, 127.0.0.1, [::1]) are exempt via address.IsLocal().

Common situations: Running fzf in a container or on a server and wanting to control it from another machine; Docker port-forwarding setups where localhost inside the container is not the host's localhost.

Related errors


AI-assisted analysis of junegunn/fzf@bd4efa277b (2026-08-15). Data as JSON: /api/errors/90868db6181b2dbf. Report an issue: GitHub.