benbjohnson/litestream · critical

failed to connect to control socket: %w

Error message

failed to connect to control socket: %w

What it means

The register command talks to the litestream daemon over a Unix control socket (custom DialContext dialing 'unix' at -socket path, default /var/run/litestream.sock). If client.Post fails — socket missing, daemon not running, socket disabled in config, permission denied, or the -timeout elapsed — the error is wrapped as 'failed to connect to control socket'.

Source

Thrown at cmd/litestream/register.go:74

		Transport: &http.Transport{
			DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
				return net.DialTimeout("unix", *socketPath, clientTimeout)
			},
		},
	}

	req := litestream.RegisterDatabaseRequest{
		Path:       dbPath,
		ReplicaURL: replicaURL,
	}
	reqBody, err := json.Marshal(req)
	if err != nil {
		return fmt.Errorf("failed to marshal request: %w", err)
	}

	resp, err := client.Post("http://localhost/register", "application/json", bytes.NewReader(reqBody))
	if err != nil {
		return fmt.Errorf("failed to connect to control socket: %w", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("failed to read response: %w", err)
	}

	if resp.StatusCode != http.StatusOK {
		var errResp litestream.ErrorResponse
		if err := json.Unmarshal(body, &errResp); err == nil && errResp.Error != "" {
			return fmt.Errorf("register failed: %s", errResp.Error)
		}
		return fmt.Errorf("register failed: %s", string(body))
	}

	var result litestream.RegisterDatabaseResponse
	if err := json.Unmarshal(body, &result); err != nil {

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Start the litestream daemon and enable the control socket with `socket.enabled: true` in the config, then restart it
  2. Confirm the socket path: `ls -l /var/run/litestream.sock` (or your -socket value) and pass -socket if it differs
  3. Check permissions — run the command as the same user that owns the socket or adjust socket ownership
  4. Increase -timeout if the daemon is slow to answer (e.g. -timeout 120)
  5. Check daemon logs for crashes and verify the daemon was started with the same config

Example fix

// before (config.yml)
// (no socket section)
// after (config.yml)
socket:
  enabled: true
Defensive patterns

Strategy: retry

Validate before calling

if [ ! -S /var/run/litestream.sock ]; then echo "control socket missing: enable socket.enabled in config and start the daemon"; exit 1; fi

Try / catch

err := registerCmd.Run(ctx, args)
if err != nil && strings.Contains(err.Error(), "failed to connect to control socket") {
    // backoff and retry a bounded number of times
    time.Sleep(2 * time.Second)
    err = registerCmd.Run(ctx, args)
}

Prevention

When it happens

Trigger: Running `litestream register` while the litestream server is not running; the IPC socket is disabled (default: socket.enabled not set to true); wrong -socket path; timeout too small; permissions on the socket file block connecting.

Common situations: User forgot to enable `socket.enabled: true` in the litestream config and restart the daemon; daemon crashed or was restarted; running as a different user than the socket owner; SELinux/AppArmor blocking /var/run/litestream.sock.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/ae30326c02591668. Report an issue: GitHub.