{"record":{"id":"dd53bad1ebddb3c6","repo":"multica-ai/multica","slug":"read-daemon-checkout-response-w","errorCode":null,"errorMessage":"read daemon checkout response: %w","messagePattern":"read daemon checkout response: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/cmd/multica/cmd_repo.go","lineNumber":391,"sourceCode":"\tctx, cancel := context.WithTimeout(parentCtx, 5*time.Minute)\n\tdefer cancel()\n\tclient := &http.Client{}\n\tcheckoutURL := fmt.Sprintf(\"http://127.0.0.1:%s/repo/checkout\", daemonPort)\n\tvar body []byte\n\tfor {\n\t\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, checkoutURL, bytes.NewReader(data))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"create daemon checkout request: %w\", err)\n\t\t}\n\t\treq.Header.Set(\"Content-Type\", \"application/json\")\n\t\tresp, err := client.Do(req)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"connect to daemon: %w\", err)\n\t\t}\n\t\tbody, err = io.ReadAll(resp.Body)\n\t\tcloseErr := resp.Body.Close()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"read daemon checkout response: %w\", err)\n\t\t}\n\t\tif closeErr != nil {\n\t\t\treturn fmt.Errorf(\"close daemon checkout response: %w\", closeErr)\n\t\t}\n\t\tif resp.StatusCode == http.StatusServiceUnavailable && resp.Header.Get(\"X-Multica-Retryable\") == \"repo-busy\" {\n\t\t\tdelay := repoCheckoutRetryDelay(resp.Header.Get(\"Retry-After\"), time.Now())\n\t\t\ttimer := time.NewTimer(delay)\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\ttimer.Stop()\n\t\t\t\treturn fmt.Errorf(\"connect to daemon: %w\", context.Cause(ctx))\n\t\t\tcase <-timer.C:\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tif resp.StatusCode != http.StatusOK {\n\t\t\treturn fmt.Errorf(\"checkout failed: %s\", string(body))\n\t\t}","sourceCodeStart":373,"sourceCodeEnd":409,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/cmd/multica/cmd_repo.go#L373-L409","documentation":"runRepoCheckout wraps io.ReadAll(resp.Body) after a successful POST to the daemon checkout endpoint. This fails only on mid-body transport errors: the daemon (or loopback stack) closes the connection before the full response is delivered, or the 5-minute context is cancelled while the body is still streaming.","triggerScenarios":"Daemon crashes or is killed while writing the response; the checkout response is large and slow enough that ctx (5-minute cap) expires mid-read; loopback connection reset (rare, e.g. socket closed by sandbox teardown).","commonSituations":"Daemon OOM-killed during a big checkout; container/namespace being torn down while the CLI still reads; response streaming blocked behind a slow git operation until the deadline hits.","solutions":["Check daemon logs for a crash/restart at the same timestamp; restart the daemon and retry the checkout.","If the cause is the 5-minute deadline, reduce checkout cost (shallow clone mode via MULTICA_REPO_CHECKOUT_MODE, narrower ref) or increase the CLI timeout.","Retry the command — checkout endpoints that already prepared the workdir usually succeed or cleanly report state on the second attempt."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"body, err := io.ReadAll(resp.Body)\nif err != nil {\n\t// transient mid-body failure: safe to retry the whole POST (checkout is keyed by url+workdir)\n\treturn fmt.Errorf(\"read daemon checkout response: %w\", err)\n}","preventionTips":["Monitor daemon memory so it is not OOM-killed mid-response.","Keep responses small/fast to stay clear of the 5-minute read deadline.","Treat read failures as retriable at the command level."],"tags":["go","http","response-body","io","daemon","transport"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}