charmbracelet/crush · error
failed to list skills: %w
Error message
failed to list skills: %w
What it means
This error is returned by Client.ListSkills when the underlying HTTP GET request to /workspaces/{id}/skills fails at the transport level. The library wraps the original error (connection failure, timeout, context cancellation, invalid URL) with %w so the root cause remains inspectable via errors.Is/As. It indicates the request never completed successfully enough to receive an HTTP response.
Source
Thrown at internal/client/config.go:223
}
defer rsp.Body.Close()
if rsp.StatusCode != http.StatusOK {
return "", fmt.Errorf("failed to get init prompt: status code %d", rsp.StatusCode)
}
var result struct {
Prompt string `json:"prompt"`
}
if err := json.NewDecoder(rsp.Body).Decode(&result); err != nil {
return "", fmt.Errorf("failed to decode init prompt response: %w", err)
}
return result.Prompt, nil
}
// ListSkills retrieves the visible skills for a workspace.
func (c *Client) ListSkills(ctx context.Context, id string) ([]proto.SkillInfo, error) {
rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/skills", id), nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to list skills: %w", err)
}
defer rsp.Body.Close()
if rsp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to list skills: status code %d", rsp.StatusCode)
}
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 {View on GitHub (pinned to 7944b8e522)
Solutions
- Verify the client's base URL/host points at a running server (curl the /health or any endpoint).
- Check network connectivity to the server (DNS, firewall, proxy, VPN).
- Inspect the wrapped cause with errors.Unwrap or %v to see the transport error (e.g. connection refused vs timeout).
- Increase or fix the context deadline passed to ListSkills if timeouts are the cause.
- Retry with backoff if the failure is transient (server restarting).
Example fix
// before
skills, err := client.ListSkills(ctx, wsID)
if err != nil { return err }
// after
skills, err := client.ListSkills(ctx, wsID)
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
return fmt.Errorf("skills listing timed out, check server health: %w", err)
}
return fmt.Errorf("is the server running? %w", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// Go: pre-check server reachability
func serverReachable(baseURL string) error {
resp, err := http.Get(baseURL + "/health")
if err != nil { return err }
defer resp.Body.Close()
return nil
} Type guard
func isTransportError(err error) bool {
var ne net.Error
return errors.As(err, &ne) || errors.Is(err, context.DeadlineExceeded) || errors.Is(err, syscall.ECONNREFUSED)
} Try / catch
skills, err := client.ListSkills(ctx, wsID)
if err != nil {
if isTransportError(err) {
// retry or surface 'server unreachable'
return retryOrFallback(err)
}
return err
} Prevention
- Health-check the server before batch operations.
- Always pass a context with a sensible timeout.
- Log errors.Unwrap output to distinguish timeout vs refusal.
- Pin and validate the base URL per environment.
When it happens
Trigger: Calling Client.ListSkills(ctx, workspaceID) when the server is unreachable, the connection is refused/reset, the context deadline expires mid-request, or c.get fails to construct/execute the request.
Common situations: Server process not running or wrong base URL/port configured; network partition, VPN or proxy blocking the request; context cancelled because a parent operation timed out; TLS certificate issues in self-hosted setups.
Related errors
- failed to read skill: %w
- failed to enable docker MCP: %w
- failed to disable docker MCP: %w
- failed to make request: %w
- failed to refresh OAuth token: %w
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/16bf29a54038c89b.
Report an issue: GitHub.