multica-ai/multica · warning

close daemon checkout response: %w

Error message

close daemon checkout response: %w

What it means

runRepoCheckout checks resp.Body.Close() after reading and fails the command if closing returns an error. Close on an HTTP response body essentially only reports a prior unread-body error; since the body was fully read by io.ReadAll beforehand, this branch is defensive and near-unreachable — it would fire if the underlying connection was already in a broken state.

Source

Thrown at server/cmd/multica/cmd_repo.go:394

	checkoutURL := fmt.Sprintf("http://127.0.0.1:%s/repo/checkout", daemonPort)
	var body []byte
	for {
		req, err := http.NewRequestWithContext(ctx, http.MethodPost, checkoutURL, bytes.NewReader(data))
		if err != nil {
			return fmt.Errorf("create daemon checkout request: %w", err)
		}
		req.Header.Set("Content-Type", "application/json")
		resp, err := client.Do(req)
		if err != nil {
			return fmt.Errorf("connect to daemon: %w", err)
		}
		body, err = io.ReadAll(resp.Body)
		closeErr := resp.Body.Close()
		if err != nil {
			return fmt.Errorf("read daemon checkout response: %w", err)
		}
		if closeErr != nil {
			return fmt.Errorf("close daemon checkout response: %w", closeErr)
		}
		if resp.StatusCode == http.StatusServiceUnavailable && resp.Header.Get("X-Multica-Retryable") == "repo-busy" {
			delay := repoCheckoutRetryDelay(resp.Header.Get("Retry-After"), time.Now())
			timer := time.NewTimer(delay)
			select {
			case <-ctx.Done():
				timer.Stop()
				return fmt.Errorf("connect to daemon: %w", context.Cause(ctx))
			case <-timer.C:
				continue
			}
		}
		if resp.StatusCode != http.StatusOK {
			return fmt.Errorf("checkout failed: %s", string(body))
		}
		break
	}

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Treat it like error 649: inspect daemon health/logs and retry the checkout.
  2. If it recurs in a specific sandbox, check whether the network namespace/proxy kills idle sockets aggressively.
Defensive patterns

Strategy: try-catch

Try / catch

if closeErr := resp.Body.Close(); closeErr != nil {
	// body already drained; close errors here are informational
	log.Printf("response close: %v", closeErr)
}

Prevention

When it happens

Trigger: The loopback connection was reset between ReadAll and Close, or a custom transport surfaced a deferred error on close; with the default transport and a fully-drained body this does not occur.

Common situations: None realistic in the current code path; would appear only under connection-level faults (sandbox tearing down sockets) racing the close call.

Related errors


AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15). Data as JSON: /api/errors/61fe1ea175ed6fa9. Report an issue: GitHub.