charmbracelet/crush · error

failed to get session agent info: status code %d

Error message

failed to get session agent info: status code %d

What it means

GetAgentSessionInfo expects 200 OK. Any other status yields this error with the numeric status code, without decoding the body. Typically 404 when the session does not exist or has ended, 401/403 for auth problems, or 5xx for server faults.

Source

Thrown at internal/client/proto.go:554

	if rsp.StatusCode != http.StatusOK {
		return proto.ShellCommandResponse{}, fmt.Errorf("failed to run shell command: status code %d", rsp.StatusCode)
	}
	var resp proto.ShellCommandResponse
	if err := json.NewDecoder(rsp.Body).Decode(&resp); err != nil {
		return proto.ShellCommandResponse{}, fmt.Errorf("failed to decode shell command response: %w", err)
	}
	return resp, nil
}

// GetAgentSessionInfo retrieves the agent session info for a workspace.
func (c *Client) GetAgentSessionInfo(ctx context.Context, id string, sessionID string) (*proto.AgentSession, error) {
	rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/agent/sessions/%s", id, sessionID), nil, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to get session agent info: %w", err)
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("failed to get session agent info: status code %d", rsp.StatusCode)
	}
	var info proto.AgentSession
	if err := json.NewDecoder(rsp.Body).Decode(&info); err != nil {
		return nil, fmt.Errorf("failed to decode session agent info: %w", err)
	}
	return &info, nil
}

// AgentSummarizeSession requests a session summarization.
func (c *Client) AgentSummarizeSession(ctx context.Context, id string, sessionID string) error {
	rsp, err := c.post(ctx, fmt.Sprintf("/workspaces/%s/agent/sessions/%s/summarize", id, sessionID), nil, nil, nil)
	if err != nil {
		return fmt.Errorf("failed to summarize session: %w", err)
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != http.StatusOK {
		return fmt.Errorf("failed to summarize session: status code %d", rsp.StatusCode)
	}

View on GitHub (pinned to 7944b8e522)

Solutions

  1. For 404, treat the session as terminated — re-create the session rather than retrying.
  2. For 401/403, refresh credentials and retry once.
  3. For 5xx, retry with backoff and check server health.
  4. Verify workspace/session IDs are current; stale IDs from a previous server instance are a frequent cause.

Example fix

// before
info, err := client.GetAgentSessionInfo(ctx, wsID, sid)
if err != nil { return false, err }
// after
info, err := client.GetAgentSessionInfo(ctx, wsID, sid)
if err != nil {
    if strings.Contains(err.Error(), "status code 404") {
        return false, nil // session gone -> not busy
    }
    return false, err
}
Defensive patterns

Strategy: fallback

Validate before calling

// Go: confirm the session was recently seen before interpreting 404 as terminal
lastSeen, seen := sessionCache[sid]
if seen && time.Since(lastSeen) < time.Minute {
    // stale-404 unlikely; treat other statuses first
}

Type guard

// Go: branch on 404 vs other statuses
func isNotFound(err error) bool {
    return strings.Contains(err.Error(), "status code 404")
}

Try / catch

info, err := client.GetAgentSessionInfo(ctx, wsID, sid)
if err != nil {
    if isNotFound(err) {
        return nil, nil // session ended -> caller treats as 'not busy'
    }
    if strings.Contains(err.Error(), "status code 401") {
        return refreshAuthAndFetch()
    }
    return nil, err
}

Prevention

When it happens

Trigger: Polling session status after the session was closed or expired (404); expired auth token (401/403); server error while assembling AgentSession info (5xx).

Common situations: AgentIsSessionBusy treating a dead session as an error instead of 'not busy'; long-lived clients whose tokens expired; races where the session is deleted between acquiring the id and polling.

Related errors


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