charmbracelet/crush · error

failed to get session: status code %d

Error message

failed to get session: status code %d

What it means

Thrown by Client.GetSession when the server returned a non-200 status for GET /workspaces/{id}/sessions/{sessionID}; the body is discarded and only the status code is reported. Callers resolveSession/resolveSessionByID use this to find a session, so a 404 here usually means the session id does not exist in that workspace.

Source

Thrown at internal/client/proto.go:615

	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)
	}
	var sess proto.Session
	if err := json.NewDecoder(rsp.Body).Decode(&sess); err != nil {
		return nil, fmt.Errorf("failed to decode session: %w", err)
	}
	return &sess, nil
}

// ListSessionHistoryFiles retrieves history files for a session as proto types.
func (c *Client) ListSessionHistoryFiles(ctx context.Context, id string, sessionID string) ([]proto.File, error) {
	rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/sessions/%s/history", id, sessionID), nil, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to get session history files: %w", err)
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("failed to get session history files: status code %d", rsp.StatusCode)
	}

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Check the status in the error: 404 → list available sessions and confirm the id exists in this workspace.
  2. Verify the workspace id matches the session's origin.
  3. Re-authenticate if the status is 401/403.
  4. Retry and check server logs for 5xx responses.

Example fix

// before
sess, err := client.GetSession(ctx, wsID, sessionID)
if err != nil {
    return err
}
// after: handle 404 as a normal "not found" outcome
sess, err := client.GetSession(ctx, wsID, sessionID)
if err != nil {
    if strings.Contains(err.Error(), "status code 404") {
        return nil, ErrSessionNotFound
    }
    return nil, err
}
Defensive patterns

Strategy: fallback

Validate before calling

// Resolve against the session list before fetching a specific session
sessions, err := client.ListSessions(ctx, wsID)
if err != nil {
    return err
}
for _, s := range sessions {
    if s.ID == sessionID {
        return nil // safe to call GetSession
    }
}
return ErrSessionNotFound

Type guard

func isNotFound(err error) bool {
    return strings.Contains(err.Error(), "status code 404")
}

Try / catch

sess, err := client.GetSession(ctx, wsID, sessionID)
if err != nil {
    if isNotFound(err) {
        // fall back to listing sessions and picking the latest
        return latestSession(ctx, wsID)
    }
    return nil, err
}

Prevention

When it happens

Trigger: Calling GetSession with a sessionID typed wrong or already deleted (404), a workspace id that does not match (404), expired auth (401/403), or a server error while loading the session row (500).

Common situations: Passing a session id from a different workspace or machine; session cleaned up by retention/pruning; typos when resuming from a saved id; auth token expiry; server DB issue producing 500.

Related errors


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