microsoft/aspire · error

connection closed

Error message

connection closed

What it means

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.

Solutions

  1. Treat "connection closed" as retryable: reconnect (re-create the client from the socket path) and re-issue in-flight requests.
  2. Check REMOTE_APP_HOST_SOCKET_PATH reachability and confirm the AppHost process is still running.
  3. Inspect errors.Join output for an underlying closeErr (e.g. use of closed connection) to find the root cause.
  4. Avoid holding long-lived connections across AppHost restarts; re-read env connection info on reconnect.

Example fix

// before
resp, err := client.Invoke(ctx, cap, args)
if err != nil {
    return err
}
// after
resp, err := client.Invoke(ctx, cap, args)
if err != nil {
    if strings.Contains(err.Error(), "connection closed") {
        client, err = reconnect() // re-dial from socket path
        if err == nil {
            resp, err = client.Invoke(ctx, cap, args)
        }
    }
    if err != nil {
        return err
    }
}
Defensive patterns

Strategy: retry

Validate before calling

if _, err := os.Stat(socketPath); err != nil {
    return fmt.Errorf("apphost socket %s unreachable: %w", socketPath, err)
}

Type guard

func isConnectionClosed(err error) bool {
    return err != nil && strings.Contains(err.Error(), "connection closed")
}

Try / catch

if err != nil {
    if isConnectionClosed(err) {
        if reerr := reconnect(); reerr == nil {
            return invokeWithRetry(ctx, cap, args) // bounded retries
        }
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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".

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 microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/a429fbebc2a17662. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.CodeGeneration.Go/Resources/transport.go:315

	go c.writeLoop()
}

func (c *connection) close(err error) {
	c.mu.Lock()
	if c.closed {
		c.mu.Unlock()
		return
	}
	c.closed = true
	pending := c.pending
	c.pending = nil
	c.mu.Unlock()

	closeErr := c.rawConn.Close()
	close(c.done)

	if err == nil {
		err = errors.New("connection closed")
	}
	if closeErr != nil {
		err = errors.Join(err, closeErr)
	}
	errResp := map[string]any{
		"error": map[string]any{
			"code":    -32000,
			"message": err.Error(),
		},
	}
	for _, ch := range pending {
		ch <- errResp
	}

	c.onClose(err)
}

func (c *connection) writeLoop() {

View on GitHub (pinned to 25830f84bd)