charmbracelet/crush · error
failed to get messages: %w
Error message
failed to get messages: %w
What it means
Thrown by Client.ListMessages in internal/client/proto.go when the HTTP GET to /workspaces/{id}/sessions/{sessionID}/messages fails at the transport level (no HTTP response at all). The wrapped c.post/c.get error is returned, indicating connectivity, DNS, timeout, or context cancellation. Called during restoreModelFromSession when restoring a TUI session.
Source
Thrown at internal/client/proto.go:594
// InitiateAgentProcessing triggers agent initialization on the server.
func (c *Client) InitiateAgentProcessing(ctx context.Context, id string, interactive bool) error {
body := jsonBody(proto.AgentInitRequest{Interactive: interactive})
rsp, err := c.post(ctx, fmt.Sprintf("/workspaces/%s/agent/init", id), nil, body, http.Header{"Content-Type": []string{"application/json"}})
if err != nil {
return fmt.Errorf("failed to initiate session agent processing: %w", err)
}
defer rsp.Body.Close()
if rsp.StatusCode != http.StatusOK {
return fmt.Errorf("failed to initiate session agent processing: status code %d", rsp.StatusCode)
}
return nil
}
// ListMessages retrieves all messages for a session as proto types.
func (c *Client) ListMessages(ctx context.Context, id string, sessionID string) ([]proto.Message, error) {
rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/sessions/%s/messages", id, sessionID), nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to get messages: %w", err)
}
defer rsp.Body.Close()
if rsp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to get messages: status code %d", rsp.StatusCode)
}
var msgs []proto.Message
if err := json.NewDecoder(rsp.Body).Decode(&msgs); err != nil && !errors.Is(err, io.EOF) {
return nil, fmt.Errorf("failed to decode messages: %w", err)
}
return msgs, nil
}
// GetSession retrieves a specific session as a proto type.
func (c *Client) GetSession(ctx context.Context, id string, sessionID string) (*proto.Session, error) {
rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/sessions/%s", id, sessionID), nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to get session: %w", err)
}View on GitHub (pinned to 7944b8e522)
Solutions
- Inspect the wrapped error to distinguish cancellation/timeout from dial failures.
- Verify the crush server is running and reachable, then retry the restore.
- If the timeout is too short, retry with a longer context deadline.
- Fix the configured server address if it no longer points at a live server.
Example fix
// before
msgs, err := client.ListMessages(ctx, wsID, sessionID)
if err != nil {
return err
}
// after: retry transient transport errors during session restore
var msgs []proto.Message
err := retry(3, 500*time.Millisecond, func() error {
var e error
msgs, e = client.ListMessages(ctx, wsID, sessionID)
return e
}) Defensive patterns
Strategy: retry
Validate before calling
// Pre-check server reachability before restoring session messages
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if _, err := client.ListSessions(ctx, wsID); err != nil {
return fmt.Errorf("cannot restore session: server unreachable: %w", err)
} Type guard
func isRetryableTransport(err error) bool {
var ne net.Error
return errors.As(err, &ne) || errors.Is(err, context.DeadlineExceeded)
} Try / catch
msgs, err := client.ListMessages(ctx, wsID, sessionID)
if err != nil && isRetryableTransport(err) {
backoff := 500 * time.Millisecond
for i := 0; i < 3; i++ {
time.Sleep(backoff)
if msgs, err = client.ListMessages(ctx, wsID, sessionID); err == nil {
break
}
backoff *= 2
}
} Prevention
- Retry ListMessages on net.Error/timeouts — message listing is idempotent
- Validate server connectivity once at session-restore startup
- Use a generous context timeout; message payloads can be large
- Keep the workspace id stable across restarts to avoid wrong-host requests
When it happens
Trigger: Calling ListMessages (or triggering restoreModelFromSession) when the server is down or restarted, the network drops mid-request, the context times out or is canceled, or DNS fails for the server host.
Common situations: Resuming a session after the server crashed; flaky Wi-Fi/VPN dropping the request; server address changed between runs; client configured against a dead port; user cancels restore and the context is canceled.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- failed to make request: %w
- failed to refresh OAuth token: %w
- failed to check project init: %w
- failed to mark project initialized: %w
- failed to get init prompt: %w
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/ff16574f1877228b.
Report an issue: GitHub.