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] = true

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Read the quoted source value and the underlying parse error in the message
  2. Correct From() to the canonical reference syntax skillref.Parse accepts
  3. Run skillref.Parse(remap.From()) in a plugin test to catch regressions
  4. 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

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


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/5cac9962a936aeae. Report an issue: GitHub.