charmbracelet/crush · error
failed to read skill: status code %d
Error message
failed to read skill: status code %d
What it means
Returned by Client.ReadSkill when the POST completed but the server replied with a non-200 status code. The library requires 200 with a proto.ReadSkillResponse body; 404 (skill or workspace not found), 401/403 (auth), or 500 all produce this error. The numeric status is embedded in the message because the body is discarded.
Source
Thrown at internal/client/config.go:246
}
var skills []proto.SkillInfo
if err := json.NewDecoder(rsp.Body).Decode(&skills); err != nil {
return nil, fmt.Errorf("failed to decode skills: %w", err)
}
return skills, nil
}
// ReadSkill reads a skill's content by ID from the server.
func (c *Client) ReadSkill(ctx context.Context, id, skillID string) (*proto.ReadSkillResponse, error) {
rsp, err := c.post(ctx, fmt.Sprintf("/workspaces/%s/skills/read", id), nil, jsonBody(proto.ReadSkillRequest{
SkillID: skillID,
}), http.Header{"Content-Type": []string{"application/json"}})
if err != nil {
return nil, fmt.Errorf("failed to read skill: %w", err)
}
defer rsp.Body.Close()
if rsp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to read skill: status code %d", rsp.StatusCode)
}
var result proto.ReadSkillResponse
if err := json.NewDecoder(rsp.Body).Decode(&result); err != nil {
return nil, fmt.Errorf("failed to decode skill response: %w", err)
}
return &result, nil
}
// MCPResourceContents holds the contents of an MCP resource.
type MCPResourceContents struct {
URI string `json:"uri"`
MIMEType string `json:"mime_type,omitempty"`
Text string `json:"text,omitempty"`
Blob []byte `json:"blob,omitempty"`
}
// EnableDockerMCP enables the Docker MCP server on the workspace.
func (c *Client) EnableDockerMCP(ctx context.Context, id string) error {View on GitHub (pinned to 7944b8e522)
Solutions
- Read the status code from the error message; for 404, re-list skills to confirm the skillID is still valid.
- For 401/403, re-authenticate or verify workspace permissions.
- For 500, check server logs for the skills/read handler failure.
- Always fetch skill IDs from a fresh ListSkills call rather than a stale cache.
- Verify the workspace ID in the URL path is correct.
Example fix
// before
skill, err := client.ReadSkill(ctx, wsID, skillID) // status code 404
// after
skills, _ := client.ListSkills(ctx, wsID)
if !containsSkill(skills, skillID) {
return fmt.Errorf("skill %s no longer exists", skillID)
}
skill, err := client.ReadSkill(ctx, wsID, skillID) Defensive patterns
Strategy: validation
Validate before calling
// Confirm the skill still exists before reading
skills, err := client.ListSkills(ctx, wsID)
if err != nil { return err }
found := false
for _, s := range skills {
if s.ID == skillID { found = true; break }
}
if !found { return fmt.Errorf("skill %s not found", skillID) } Type guard
func isNon200(err error) (code int, ok bool) {
m := regexp.MustCompile(`status code (\d+)`).FindStringSubmatch(err.Error())
if len(m) < 2 { return 0, false }
code, err2 := strconv.Atoi(m[1])
return code, err2 == nil
} Try / catch
skill, err := client.ReadSkill(ctx, wsID, skillID)
if err != nil {
if code, ok := isNon200(err); ok && code == 404 {
return ErrSkillNotFound // handle gracefully
}
return err
} Prevention
- Always source skill IDs from a fresh ListSkills call.
- Handle 404 as a normal 'skill gone' case, not a crash.
- Keep auth tokens valid; re-auth on 401/403.
- Check server logs for 500s on the skills/read route.
When it happens
Trigger: Calling ReadSkill with a skillID that no longer exists (404), with insufficient permissions (403), an invalid workspace ID (404), or during a server-side failure (500).
Common situations: Skill deleted or renamed by another agent/user before the read; listing skills, then reading from a stale cached list; expired session token; server bug returning 500 for large skill files.
Related errors
- failed to list skills: status code %d
- failed to enable docker MCP: status code %d
- failed to disable docker MCP: status code %d
- failed to refresh OAuth token: status code %d
- failed to check project init: status code %d
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/d351192ed58beee6.
Report an issue: GitHub.