charmbracelet/crush · warning
errors.New(s.Error)
Error message
errors.New(s.Error)
What it means
Not a distinct error string but a re-wrapping site: when a skill's discovery state carries a non-empty Error string, the workspace converts it into a Go error via errors.New(s.Error) and attaches it to the SkillState. The actual message text comes from the skill loader/discovery layer.
Source
Thrown at internal/workspace/client_workspace.go:1389
}
}
// protoToSkillStates reconstructs internal skill state slices from
// their wire representation. Non-empty Error strings are turned into
// synthetic error values; the TUI never type-asserts on Err.
func protoToSkillStates(in []proto.SkillState) []*skills.SkillState {
if len(in) == 0 {
return nil
}
out := make([]*skills.SkillState, len(in))
for i, s := range in {
state := &skills.SkillState{
Name: s.Name,
Path: s.Path,
State: skills.DiscoveryState(s.State),
}
if s.Error != "" {
state.Err = errors.New(s.Error)
}
out[i] = state
}
return out
}
func todosToProto(todos []session.Todo) []proto.Todo {
if len(todos) == 0 {
return nil
}
out := make([]proto.Todo, len(todos))
for i, t := range todos {
out[i] = proto.Todo{
Content: t.Content,
Status: string(t.Status),
ActiveForm: t.ActiveForm,
}
}View on GitHub (pinned to 7944b8e522)
Solutions
- Read state.Err's message to find the failing skill and fix its SKILL.md/frontmatter
- Verify the skill path exists and is readable
- Re-run the skills command after fixing; disable the broken skill if it's third-party
Example fix
// before
if s.Error != "" {
state.Err = errors.New(s.Error)
}
// after
if s.Error != "" {
state.Err = fmt.Errorf("skill %q: %w", s.Name, errors.New(s.Error))
} Defensive patterns
Strategy: type-guard
Validate before calling
for _, s := range skillStates {
if s.Error != "" {
log.Printf("skill %s failed discovery: %s", s.Name, s.Error)
}
} Type guard
func (st *skills.SkillState) HasError() bool { return st.Err != nil } Try / catch
if state.Err != nil {
var skillErr *os.PathError
if errors.As(state.Err, &skillErr) {
// handle missing/unreadable skill file
}
} Prevention
- Validate skill SKILL.md frontmatter before installing
- Keep skill directories readable and present
- Re-check skill health after Crush upgrades or path changes
When it happens
Trigger: Listing/updating skills where one or more skill files failed discovery — malformed frontmatter, unreadable path, invalid SKILL.md — so s.Error is populated and gets converted here.
Common situations: Skill file with broken YAML frontmatter; skill directory removed after registration (permission denied); a skill schema mismatch after a Crush version upgrade.
Related errors
- agent coordinator not initialized
- client not attached
- workspace closing
- requested channels differ from the existing workspace; chann
- not found
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/4ed7ff2320586f5d.
Report an issue: GitHub.