charmbracelet/crush · error

failed to get messages: status code

Error message

failed to get messages: status code %d

What it means

Thrown by Client.ListMessages when the server returned a status other than 200 for GET /workspaces/{id}/sessions/{sessionID}/messages. The response body is not read, so only the numeric status is available. During restoreModelFromSession this prevents the conversation history from being restored.

Solutions

  1. Check the status code embedded in the error: 404 means the session is gone — start a new session or pick a different one.
  2. Verify the workspace id matches the one the session was created under.
  3. Re-authenticate if the status is 401/403.
  4. Check server logs and retry if the status is 5xx (transient server fault).

Example fix

// before
msgs, err := client.ListMessages(ctx, wsID, sessionID)
if err != nil {
    return fmt.Errorf("restore failed: %w", err)
}
// after: distinguish missing session from transient failure
msgs, err := client.ListMessages(ctx, wsID, sessionID)
if err != nil {
    if strings.Contains(err.Error(), "status code 404") {
        return ErrSessionNotFound
    }
    return fmt.Errorf("restore failed, retrying may help: %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the session exists before restoring messages
sessions, err := client.ListSessions(ctx, wsID)
if err != nil {
    return err
}
found := false
for _, s := range sessions {
    if s.ID == sessionID {
        found = true
        break
    }
}
if !found {
    return fmt.Errorf("session %s not in workspace %s", sessionID, wsID)
}

Type guard

func listMessagesStatus(err error) int {
    var code int
    if _, scanErr := fmt.Sscanf(err.Error(), "failed to get messages: status code %d", &code); scanErr == nil {
        return code
    }
    return 0
}

Try / catch

msgs, err := client.ListMessages(ctx, wsID, sessionID)
if err != nil {
    if listMessagesStatus(err) == 404 {
        return startFreshSession(ctx) // graceful degradation
    }
    return fmt.Errorf("message restore failed: %w", err)
}

Prevention

When it happens

Trigger: Calling ListMessages for a sessionID that does not exist (404), an invalid workspace id, auth rejection (401/403), or a server-side failure while enumerating messages (500).

Common situations: Restoring a session that was deleted on another machine; workspace id drift after re-cloning or moving the project; expired auth token; server bug or DB corruption producing 500.

Related errors


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

Appendix: source

Thrown at internal/client/proto.go:598

	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)
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("failed to get session: status code %d", rsp.StatusCode)
	}

View on GitHub (pinned to 7944b8e522)