charmbracelet/crush · error

failed to get messages: status code %d

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.

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)

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.