charmbracelet/crush · error

failed to get sessions: %w

Error message

failed to get sessions: %w

What it means

ListSessions failed inside c.get before a response was available; the transport error is wrapped with this message. The GET to /workspaces/{id}/sessions never completed — connection failure, DNS error, TLS problem, or context cancellation.

Source

Thrown at internal/client/proto.go:662

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

// ListSessions lists all sessions in a workspace as proto types.
func (c *Client) ListSessions(ctx context.Context, id string) ([]proto.Session, error) {
	rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/sessions", id), nil, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to get sessions: %w", err)
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("failed to get sessions: status code %d", rsp.StatusCode)
	}
	var sessions []proto.Session
	if err := json.NewDecoder(rsp.Body).Decode(&sessions); err != nil {
		return nil, fmt.Errorf("failed to decode sessions: %w", err)
	}
	return sessions, nil
}

// GrantPermission grants a permission on a workspace. The returned
// bool reports whether this call resolved the pending request (true)
// or found it already resolved by a previous caller (false). A false
// value is not an error — it just means another subscriber resolved
// the same request first.
func (c *Client) GrantPermission(ctx context.Context, id string, req proto.PermissionGrant) (bool, error) {

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Inspect the wrapped error for the root cause.
  2. Verify the server address and workspace ID.
  3. Retry with backoff on transient errors.
  4. Increase context timeout if listing large workspaces times out.
  5. Check network/VPN/TLS configuration.

Example fix

// before
sessions, err := client.ListSessions(ctx, wsID)
if err != nil { return err }
// after
sessions, err := client.ListSessions(ctx, wsID)
if err != nil {
    var netErr net.Error
    if errors.As(err, &netErr) && netErr.Timeout() {
        // retry with longer deadline/backoff
    }
    return err
}
Defensive patterns

Strategy: retry

Validate before calling

if wsID == "" { return errors.New("workspace id required") }
if err := ctx.Err(); err != nil { return err }

Type guard

func isListTransportError(err error) bool {
    var netErr net.Error
    return err != nil && errors.As(err, &netErr)
}

Try / catch

sessions, err := client.ListSessions(ctx, wsID)
if err != nil {
    if isListTransportError(err) {
        return retryWithBackoff(3, func() error {
            sessions, err = client.ListSessions(ctx, wsID)
            return err
        })
    }
    return err
}

Prevention

When it happens

Trigger: GET /workspaces/{id}/sessions fails at the transport layer: server unreachable, connection reset, ctx deadline exceeded, or invalid characters in the workspace ID.

Common situations: Wrong base URL or server down; offline/VPN drop; timeout on large workspaces; workspace ID with characters needing URL escaping.

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/bd8e92ab4d060783. Report an issue: GitHub.