charmbracelet/crush · error
failed to decode session: %w
Error message
failed to decode session: %w
What it means
GetSession successfully reached the workspace server's /workspaces/{id}/sessions/{sid} endpoint (HTTP 200), but the JSON response body could not be decoded into proto.Session. The client wraps the json.Decoder error with this message. It indicates the server returned 200 with a body that is not a valid or expected Session JSON document.
Source
Thrown at internal/client/proto.go:619
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)
}
var files []proto.File
if err := json.NewDecoder(rsp.Body).Decode(&files); err != nil {
return nil, fmt.Errorf("failed to decode session history files: %w", err)
}View on GitHub (pinned to 7944b8e522)
Solutions
- Log the wrapped error (err) to see the exact JSON decode failure (unexpected EOF, type mismatch, invalid character).
- Re-run with a matching server version so the Session JSON schema matches the client's proto.Session.
- Call the endpoint manually (curl) and inspect the raw 200 body for HTML/truncation.
- Check for proxies/middleware that rewrite responses.
- Retry the request in case of a truncated response.
Example fix
// before
sess, err := client.GetSession(ctx, wsID, sessID)
if err != nil { return err }
// after
sess, err := client.GetSession(ctx, wsID, sessID)
if err != nil {
if strings.Contains(err.Error(), "failed to decode session") {
// inspect/refresh server or retry
return fmt.Errorf("server returned unparseable session payload: %w", err)
}
return err
} Defensive patterns
Strategy: try-catch
Validate before calling
// Verify connectivity before calling:
if err := client.ping(ctx); err != nil {
return fmt.Errorf("server unreachable: %w", err)
} Type guard
func isDecodeError(err error) bool {
return err != nil && strings.Contains(err.Error(), "failed to decode session")
} Try / catch
sess, err := client.GetSession(ctx, wsID, sessID)
if err != nil {
if isDecodeError(err) {
// server returned unparseable payload; retry or inspect server
return fmt.Errorf("malformed session response for %s: %w", sessID, err)
}
return err
} Prevention
- Keep client and server versions in sync.
- Check proxies that return 200 with non-JSON bodies.
- Log wrapped errors to surface the underlying JSON cause.
- Retry on transient truncation errors.
When it happens
Trigger: GET /workspaces/{id}/sessions/{sid} returns 200 but the body is not JSON (e.g. an HTML error page from a proxy), is truncated, or its fields do not match proto.Session's JSON schema.
Common situations: A reverse proxy or auth layer intercepts the request and returns 200 with HTML; server/client version skew where Session fields changed; server bug returning empty or partial body.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- failed to decode session history files: %w
- failed to decode sessions: %w
- server health check failed: %s
- server shutdown failed: %s
- failed to set compact mode: status code %d
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/df246cb039569fa0.
Report an issue: GitHub.