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

  1. Inspect the wrapped error to distinguish cancellation/timeout from dial failures.
  2. Verify the crush server is running and reachable, then retry the restore.
  3. If the timeout is too short, retry with a longer context deadline.
  4. 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

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


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/ff16574f1877228b. Report an issue: GitHub.