benbjohnson/litestream · error

failed to connect to control socket: %w

Error message

failed to connect to control socket: %w

What it means

The `litestream start` CLI failed to make an HTTP POST to the daemon's control API. The client dials a Unix socket (default /var/run/litestream.sock) via a custom Transport, so any dial error, timeout, or connection reset surfaces here wrapped as 'failed to connect to control socket'. It means the CLI could not reach the running litestream daemon at all — the request never got a response.

Source

Thrown at cmd/litestream/start.go:65

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

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

	resp, err := client.Post("http://localhost/start", "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("start failed: %s", errResp.Error)
		}
		return fmt.Errorf("start failed: %s", string(body))
	}

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

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Verify the litestream daemon is running and was started with socket.enabled: true in its config
  2. Pass -socket with the exact same path the daemon listens on (default /var/run/litestream.sock)
  3. Check the socket file exists and is accessible: ls -l /var/run/litestream.sock
  4. Increase -timeout if the daemon is slow to accept connections
  5. Run the CLI in the same host/container/namespace as the daemon

Example fix

// before
litestream start /path/to/db
// after
# start daemon with IPC socket enabled (config: socket.enabled: true), then:
litestream start -socket /var/run/litestream.sock -timeout 30 /path/to/db
Defensive patterns

Strategy: fallback

Validate before calling

if [ ! -S /var/run/litestream.sock ]; then echo 'control socket missing — is the daemon running with socket.enabled: true?'; exit 1; fi

Try / catch

if err := startCmd.Run(ctx, args); err != nil {
    if strings.Contains(err.Error(), "failed to connect to control socket") {
        // check daemon health / socket path before surfacing
    }
}

Prevention

When it happens

Trigger: Running `litestream start /path/to/db` when the daemon is not running, the -socket path does not match the daemon's socket (IPC socket is disabled by default — must enable socket.enabled: true in config), the socket file was deleted, or the -timeout seconds elapse before the dial/handshake completes.

Common situations: Operator forgot to enable the IPC socket in the daemon config or used a non-default -socket path on only one side; daemon crashed or was restarted; running the CLI in a different mount namespace/container than the daemon so /var/run/litestream.sock is absent; socket permission denied for the current user.

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/97fc89daef41577f. Report an issue: GitHub.