{"record":{"id":"16b711ed224feb79","repo":"charmbracelet/crush","slug":"failed-to-decode-skill-response-w","errorCode":null,"errorMessage":"failed to decode skill response: %w","messagePattern":"failed to decode skill response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/client/config.go","lineNumber":250,"sourceCode":"\t}\n\treturn skills, nil\n}\n\n// ReadSkill reads a skill's content by ID from the server.\nfunc (c *Client) ReadSkill(ctx context.Context, id, skillID string) (*proto.ReadSkillResponse, error) {\n\trsp, err := c.post(ctx, fmt.Sprintf(\"/workspaces/%s/skills/read\", id), nil, jsonBody(proto.ReadSkillRequest{\n\t\tSkillID: skillID,\n\t}), http.Header{\"Content-Type\": []string{\"application/json\"}})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read skill: %w\", err)\n\t}\n\tdefer rsp.Body.Close()\n\tif rsp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"failed to read skill: status code %d\", rsp.StatusCode)\n\t}\n\tvar result proto.ReadSkillResponse\n\tif err := json.NewDecoder(rsp.Body).Decode(&result); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode skill response: %w\", err)\n\t}\n\treturn &result, nil\n}\n\n// MCPResourceContents holds the contents of an MCP resource.\ntype MCPResourceContents struct {\n\tURI      string `json:\"uri\"`\n\tMIMEType string `json:\"mime_type,omitempty\"`\n\tText     string `json:\"text,omitempty\"`\n\tBlob     []byte `json:\"blob,omitempty\"`\n}\n\n// EnableDockerMCP enables the Docker MCP server on the workspace.\nfunc (c *Client) EnableDockerMCP(ctx context.Context, id string) error {\n\trsp, err := c.post(ctx, fmt.Sprintf(\"/workspaces/%s/mcp/docker/enable\", id), nil, nil, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to enable docker MCP: %w\", err)\n\t}","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/client/config.go#L232-L268","documentation":"Returned by Client.ReadSkill when the server returned 200 OK but the body failed to decode into proto.ReadSkillResponse. Typical causes are an empty body, malformed JSON, or a payload whose fields don't match the proto.ReadSkillResponse struct. It signals a broken response contract rather than a request problem.","triggerScenarios":"Server handler for /workspaces/{id}/skills/read returns 200 with an error JSON object, null body, truncated output, or renamed fields inconsistent with proto.ReadSkillResponse.","commonSituations":"Server version drift after an API change; middleware or compression misconfiguration corrupting the body; a skill whose content contains bytes that break encoding on the server side.","solutions":["Capture the raw body via server logs or a proxy to see the actual 200 payload.","Compare the payload against proto.ReadSkillResponse's json tags and update the mismatched side.","Upgrade client or server so both agree on the read-skills response schema.","Check for body-corrupting middleware (compression, charset, truncation).","Reproduce with curl -X POST .../skills/read and validate the JSON with jq."],"exampleFix":"// before\nr, err := client.ReadSkill(ctx, wsID, skillID) // decode error on 200\n// after\n// Verify shape: curl -s -X POST $BASE/workspaces/$WS/skills/read -d '{\"skill_id\":\"...\"}' | jq\nr, err := client.ReadSkill(ctx, wsID, skillID)\nif err != nil {\n    return fmt.Errorf(\"unexpected read-skill response; check server version: %w\", err)\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isDecodeError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"failed to decode skill response\")\n}\n\nfunc validReadSkillResponse(r *proto.ReadSkillResponse) bool {\n    return r != nil && r.Content != \"\"\n}","tryCatchPattern":"skill, err := client.ReadSkill(ctx, wsID, skillID)\nif err != nil {\n    if isDecodeError(err) {\n        // contract mismatch on 200 body; fall back or surface version skew\n        return fmt.Errorf(\"server response incompatible: %w\", err)\n    }\n    return err\n}\nif !validReadSkillResponse(skill) {\n    return ErrMalformedSkillPayload\n}","preventionTips":["Validate the response shape with curl/jq after server upgrades.","Version-gate client/server compatibility.","Guard against middleware that mutates response bodies.","After decode, validate required fields before use."],"tags":["http-client","json-decode","skills","contract-mismatch"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}