geektutu/7days-golang · error
connection is shut down
Error message
connection is shut down
What it means
ErrShutdown is the sentinel error returned when operating on a Client whose connection has been closed by the user (client.closing) or shut down by the server (client.shutdown). Calls made afterwards fail immediately instead of being sent.
Source
Thrown at gee-rpc/day7-registry/client.go:55
// Client represents an RPC Client.
// There may be multiple outstanding Calls associated
// with a single Client, and a Client may be used by
// multiple goroutines simultaneously.
type Client struct {
cc codec.Codec
opt *Option
sending sync.Mutex // protect following
header codec.Header
mu sync.Mutex // protect following
seq uint64
pending map[uint64]*Call
closing bool // user has called Close
shutdown bool // server has told us to stop
}
var _ io.Closer = (*Client)(nil)
var ErrShutdown = errors.New("connection is shut down")
// Close the connection
func (client *Client) Close() error {
client.mu.Lock()
defer client.mu.Unlock()
if client.closing {
return ErrShutdown
}
client.closing = true
return client.cc.Close()
}
// IsAvailable return true if the client does work
func (client *Client) IsAvailable() bool {
client.mu.Lock()
defer client.mu.Unlock()
return !client.shutdown && !client.closing
}View on GitHub (pinned to cf36443821)
Solutions
- Recreate the client (geeRPC.XDial / dialTimeout) after ErrShutdown and retry the request once.
- Keep a single owner of the client lifecycle; call Close exactly once via defer.
- Detect ErrShutdown (errors.Is / equality) and rebuild the connection rather than re-calling on the same client.
Example fix
// before
err := client.Call(ctx, "Foo.Sum", req, reply) // ErrShutdown if connection died
// after
err := client.Call(ctx, "Foo.Sum", req, reply)
if err == geeRPC.ErrShutdown {
client, err = geeRPC.XDial(serverAddr)
if err == nil { err = client.Call(ctx, "Foo.Sum", req, reply) }
} Defensive patterns
Strategy: retry
Validate before calling
client.mu.Lock()
closed := client.closing || client.shutdown
client.mu.Unlock()
if closed { client, _ = geeRPC.XDial(addr) } // rebuild before calling Try / catch
if err := client.Call(ctx, "Foo.Sum", args, reply); err == geeRPC.ErrShutdown {
client, err = geeRPC.XDial(addr)
if err == nil { err = client.Call(ctx, "Foo.Sum", args, reply) }
} Prevention
- Always create the client lazily and reconnect on ErrShutdown.
- Call Close exactly once, via defer in the client's owner.
- Treat any Call error on a long-lived client as a signal to check connection health.
When it happens
Trigger: Calling client.Call/Go after client.Close(); using a client after receive() hit an error and terminateCalls set shutdown; or calling Close() twice in defer + explicit code paths.
Common situations: Connection dropped (server restart, network cut) so the client auto-shuts down and later calls fail; reusing a cached client past its lifetime; double-Close in defer handlers; load balancer dialing a dead server then reusing the failed client.
Related errors
- connection is shut down
- connection is shut down
- reading body
- rpc client: call failed:
- number of options is more than 1
AI-assisted analysis of geektutu/7days-golang@cf36443821 (2026-09-03).
Data as JSON: /api/errors/39cb9ac7a82d30c3.
Report an issue: GitHub.