charmbracelet/crush · error
failed to decode LSPs: %w
Error message
failed to decode LSPs: %w
What it means
GetLSPs received a 200 response but json.Decode failed to unmarshal the body into map[string]proto.LSPClientInfo. The payload did not match the expected LSP client state schema.
Source
Thrown at internal/client/proto.go:309
if err := json.NewDecoder(rsp.Body).Decode(&diagnostics); err != nil {
return nil, fmt.Errorf("failed to decode LSP diagnostics: %w", err)
}
return diagnostics, nil
}
// GetLSPs retrieves the LSP client states for a workspace.
func (c *Client) GetLSPs(ctx context.Context, id string) (map[string]proto.LSPClientInfo, error) {
rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/lsps", id), nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to get LSPs: %w", err)
}
defer rsp.Body.Close()
if rsp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to get LSPs: status code %d", rsp.StatusCode)
}
var lsps map[string]proto.LSPClientInfo
if err := json.NewDecoder(rsp.Body).Decode(&lsps); err != nil {
return nil, fmt.Errorf("failed to decode LSPs: %w", err)
}
return lsps, nil
}
// MCPGetStates retrieves the MCP client states for a workspace.
func (c *Client) MCPGetStates(ctx context.Context, id string) (map[string]proto.MCPClientInfo, error) {
rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/mcp/states", id), nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to get MCP states: %w", err)
}
defer rsp.Body.Close()
if rsp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to get MCP states: status code %d", rsp.StatusCode)
}
var states map[string]proto.MCPClientInfo
if err := json.NewDecoder(rsp.Body).Decode(&states); err != nil {
return nil, fmt.Errorf("failed to decode MCP states: %w", err)
}View on GitHub (pinned to 7944b8e522)
Solutions
- Match client and server versions; rebuild the client against the current proto package.
- Capture the raw body and log it alongside the decode error to identify schema drift.
- Bypass or reconfigure proxies that may alter the response body.
- Restart the server if truncation is suspected.
Example fix
// before
var lsps map[string]proto.LSPClientInfo
if err := json.NewDecoder(rsp.Body).Decode(&lsps); err != nil { return nil, err }
// after
body, _ := io.ReadAll(rsp.Body)
var lsps map[string]proto.LSPClientInfo
if err := json.Unmarshal(body, &lsps); err != nil {
return nil, fmt.Errorf("failed to decode LSPs: %w (body: %.200s)", err, body)
} Defensive patterns
Strategy: type-guard
Validate before calling
body, _ := io.ReadAll(rsp.Body)
var probe map[string]json.RawMessage
if err := json.Unmarshal(body, &probe); err != nil { return fmt.Errorf("LSPs payload is not an object: %w", err) } Type guard
func isLSPClientInfoMap(v any) (map[string]proto.LSPClientInfo, bool) {
m, ok := v.(map[string]proto.LSPClientInfo)
return m, ok && v != nil
} Try / catch
var lsps map[string]proto.LSPClientInfo
if err := json.Unmarshal(body, &lsps); err != nil {
return nil, fmt.Errorf("unexpected LSPs payload (server/client version mismatch?): %w", err)
} Prevention
- Upgrade client and server together — proto structs must match the wire format.
- Probe with map[string]json.RawMessage when debugging schema drift.
- Log the first ~200 bytes of any body that fails to decode.
- Disable response-modifying proxies in dev environments.
When it happens
Trigger: Calling GetLSPs when the server returns unexpected JSON: an array instead of an object, a field type change in LSPClientInfo after a version bump, an empty/garbage body, or a proxy substituting content.
Common situations: Client/server skew after upgrading one side; middlewares (auth proxies, injectors) rewriting responses; server bug emitting partial JSON for many LSPs.
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 LSP diagnostics: %w
- failed to decode MCP states: %w
- failed to decode response: %w
- failed to read file: %w
- failed to marshal GraphQL request: %w
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/f5e6723380e8161e.
Report an issue: GitHub.