{"record":{"id":"a429fbebc2a17662","repo":"microsoft/aspire","slug":"connection-closed-transport","errorCode":null,"errorMessage":"connection closed","messagePattern":"connection closed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.CodeGeneration.Go/Resources/transport.go","lineNumber":315,"sourceCode":"\tgo c.writeLoop()\n}\n\nfunc (c *connection) close(err error) {\n\tc.mu.Lock()\n\tif c.closed {\n\t\tc.mu.Unlock()\n\t\treturn\n\t}\n\tc.closed = true\n\tpending := c.pending\n\tc.pending = nil\n\tc.mu.Unlock()\n\n\tcloseErr := c.rawConn.Close()\n\tclose(c.done)\n\n\tif err == nil {\n\t\terr = errors.New(\"connection closed\")\n\t}\n\tif closeErr != nil {\n\t\terr = errors.Join(err, closeErr)\n\t}\n\terrResp := map[string]any{\n\t\t\"error\": map[string]any{\n\t\t\t\"code\":    -32000,\n\t\t\t\"message\": err.Error(),\n\t\t},\n\t}\n\tfor _, ch := range pending {\n\t\tch <- errResp\n\t}\n\n\tc.onClose(err)\n}\n\nfunc (c *connection) writeLoop() {","sourceCodeStart":297,"sourceCodeEnd":333,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.CodeGeneration.Go/Resources/transport.go#L297-L333","documentation":"When the Go transport's Close runs without a prior error, it synthesizes \"connection closed\" as the error accompanying the close, then sends an error response over the wire. Callers of close (writeLoop, readLoop, or an outer close) surface this whenever the connection is torn down while work is pending, optionally joined with the underlying rawConn.Close() error.","triggerScenarios":"Server or client drops the socket mid-session; writeLoop/readLoop detects a failed connection and calls close; code calls Close explicitly while requests are in flight, so pending calls get \"connection closed\" as their error.","commonSituations":"AppHost process exits or restarts while the Go client is connected; idle timeout or keepalive failure silently ending the session; firewall/network interruption; double-close patterns where the second close reports \"connection closed\".","solutions":["Treat \"connection closed\" as retryable: reconnect (re-create the client from the socket path) and re-issue in-flight requests.","Check REMOTE_APP_HOST_SOCKET_PATH reachability and confirm the AppHost process is still running.","Inspect errors.Join output for an underlying closeErr (e.g. use of closed connection) to find the root cause.","Avoid holding long-lived connections across AppHost restarts; re-read env connection info on reconnect."],"exampleFix":"// before\nresp, err := client.Invoke(ctx, cap, args)\nif err != nil {\n    return err\n}\n// after\nresp, err := client.Invoke(ctx, cap, args)\nif err != nil {\n    if strings.Contains(err.Error(), \"connection closed\") {\n        client, err = reconnect() // re-dial from socket path\n        if err == nil {\n            resp, err = client.Invoke(ctx, cap, args)\n        }\n    }\n    if err != nil {\n        return err\n    }\n}","handlingStrategy":"retry","validationCode":"if _, err := os.Stat(socketPath); err != nil {\n    return fmt.Errorf(\"apphost socket %s unreachable: %w\", socketPath, err)\n}","typeGuard":"func isConnectionClosed(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"connection closed\")\n}","tryCatchPattern":"if err != nil {\n    if isConnectionClosed(err) {\n        if reerr := reconnect(); reerr == nil {\n            return invokeWithRetry(ctx, cap, args) // bounded retries\n        }\n    }\n    return err\n}","preventionTips":["Wrap RPC calls in bounded reconnect-and-retry logic.","Monitor AppHost process health; restarts manifest as this error.","Re-read connection env vars on reconnect instead of caching them.","Log errors.Join contents to distinguish synthetic close from real closeErr."],"tags":["go","network","connection","transport"],"backgroundTag":"connection-refused","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}