microsoft/aspire · error
not connected to AppHost
Error message
not connected to AppHost
What it means
This error is returned by the JSON-RPC connection's sendRequest when the connection has already been closed (c.closed is true) at the moment a request is queued or while it is awaiting a response. It indicates the AppHost server side of the Unix-socket transport is gone (disconnected, shut down, or never fully started), so pending JSON-RPC calls cannot be delivered or answered.
Solutions
- Check that the AppHost is still running (`aspire run` active) before or while making calls
- Reconnect by calling CreateBuilder again (connect is idempotent and re-establishes c.conn) or implement a reconnect-on-disconnect loop via client.onDisconnect
- Wrap calls in retry logic that treats this error as a transient disconnection and re-attempts after reconnecting
- Verify no earlier authentication or connection error silently tore down the connection; log onDisconnect callbacks
Example fix
// before
builder, err := CreateBuilder(ctx) // AppHost may have exited
// after
builder, err := CreateBuilder(ctx)
if err != nil {
if strings.Contains(err.Error(), "not connected to AppHost") {
time.Sleep(retryDelay)
builder, err = CreateBuilder(ctx) // reconnect and retry
}
if err != nil {
log.Fatal(err)
}
} Defensive patterns
Strategy: try-catch
Validate before calling
if client == nil || !clientHealthy(client) {
// skip the call and (re)connect first
} Type guard
func isConnected(c *AppHostClient) bool {
return c != nil && c.Connected()
} Try / catch
builder, err := CreateBuilder(ctx)
if err != nil {
if strings.Contains(err.Error(), "not connected to AppHost") {
// reconnect + retry with backoff
}
return err
} Prevention
- Keep the AppHost process alive for the client's whole lifetime
- Register onDisconnect to detect drops early and trigger reconnect
- Add retry-with-backoff around capability calls treating this as transient
- Check the error returned by CreateBuilder before using any derived handles
When it happens
Trigger: Calling any generated capability-invoking API after the AppHost server closed the socket: (1) the writeQueue send races with connection close (line 452), (2) the connection's done channel fires while the request is queued (line 468) or while waiting for the response and no response arrived (line 484). Typically triggered by AppHost process exit, server-initiated disconnect, or calling APIs after a prior error tore the connection down.
Common situations: The `aspire run` AppHost was stopped or crashed while the generated Go client was mid-operation; long-running requests outliving the AppHost; calling client APIs after an authentication failure caused connect() to disconnect; reusing a client whose connection was dropped by the onConnectionClose handler.
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
- -32000
- connection closed
- -32603
- ASPIRE_REMOTE_APPHOST_TOKEN environment variable is not set
- callback ID missing
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/e232093efd51701e.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.CodeGeneration.Go/Resources/transport.go:452
ctx = context.Background()
}
if err := ctx.Err(); err != nil {
return nil, err
}
id := c.nextID.Add(1)
respCh := make(chan map[string]any, 1)
msg := map[string]any{
"jsonrpc": "2.0",
"id": id,
"method": method,
"params": params,
}
c.mu.Lock()
if c.closed {
c.mu.Unlock()
return nil, errors.New("not connected to AppHost")
}
c.pending[id] = respCh
c.mu.Unlock()
select {
case c.writeQueue <- msg:
case <-ctx.Done():
c.mu.Lock()
delete(c.pending, id)
c.mu.Unlock()
return nil, ctx.Err()
case <-c.done:
c.mu.Lock()
delete(c.pending, id)
c.mu.Unlock()
return nil, errors.New("not connected to AppHost")
}
View on GitHub (pinned to 25830f84bd)