larksuite/cli · error · skillref.ErrInvalidRemap
%w: source %q: %w
Error message
%w: source %q: %w
What it means
resolveReferences could not parse the remap's source ('From') string into a skill reference; it wraps skillref.ErrInvalidRemap with the offending string and the parse error. Remap endpoints must be valid canonical skill references.
Source
Thrown at internal/skillpolicy/resolver.go:133
composed := newOverlayFS(lowerSnapshot, upperSnapshot, spec.Remove, spec.Allow)
if err := validateRequiredSkills(composed); err != nil {
return Resolution{}, fmt.Errorf("plugin %q skill spec: %w", owner, err)
}
content = composed
}
refs, err := resolveReferences(content, spec.ReferenceRemaps)
if err != nil {
return Resolution{}, fmt.Errorf("plugin %q skill spec: %w", owner, err)
}
return Resolution{Content: content, References: refs}, nil
}
func resolveReferences(content fs.FS, remaps []platform.SkillRefRemap) (*skillref.Resolver, error) {
mappings := make([]skillref.Mapping, 0, len(remaps))
for _, remap := range remaps {
from, err := skillref.Parse(remap.From())
if err != nil {
return nil, fmt.Errorf("%w: source %q: %w", skillref.ErrInvalidRemap, remap.From(), err)
}
to, err := skillref.Parse(remap.To())
if err != nil {
return nil, fmt.Errorf("%w: target %q: %w", skillref.ErrInvalidRemap, remap.To(), err)
}
mappings = append(mappings, skillref.Mapping{From: from, To: to})
}
return skillref.New(content, mappings)
}
// distinctOwners returns the unique contributing plugin names in
// first-seen order. Mirrors cmdpolicy.distinctOwners.
func distinctOwners(specs []PluginSkill) []string {
seen := map[string]bool{}
owners := make([]string, 0, len(specs))
for _, s := range specs {
if !seen[s.PluginName] {
seen[s.PluginName] = trueView on GitHub (pinned to 7fd6ef3c07)
Solutions
- Read the quoted source value and the underlying parse error in the message
- Correct From() to the canonical reference syntax skillref.Parse accepts
- Run skillref.Parse(remap.From()) in a plugin test to catch regressions
- If the source skill was renamed, update the remap's From to the new name
Example fix
// before
platform.NewSkillRefRemap("Skills/Deploy", "release")
// after
platform.NewSkillRefRemap("deploy", "release") Defensive patterns
Strategy: validation
Validate before calling
if _, err := skillref.Parse(remap.From()); err != nil {
return fmt.Errorf("invalid remap source %q: %w", remap.From(), err)
} Try / catch
_, err := skillpolicy.ResolveWithReferences(base, specs)
if errors.Is(err, skillref.ErrInvalidRemap) { /* fix From value */ } Prevention
- Run skillref.Parse on every From at plugin init
- Use canonical skill names without paths or case drift
- Update remaps whenever a source skill is renamed
When it happens
Trigger: A plugin's SkillsOverlay.ReferenceRemaps contains an entry whose From() fails skillref.Parse: empty string, invalid skill name, or a path/reference shape the parser rejects. Reached only via ResolveWithReferences with at least one remap.
Common situations: Hand-written remap tables with typos ('Code-Review'), path fragments ('skills/x/SKILL.md'), or a From value that predates a skill rename in a newer plugin version.
Related errors
- %w: target %q: %w
- %w: source %q: %w
- invalid skill reference remap
- parse policy yaml: %w
- skill reference is empty
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/5cac9962a936aeae.
Report an issue: GitHub.