larksuite/cli · error · ErrInvalidRemap
%w: source %q: %w
Error message
%w: source %q: %w
What it means
skillref.New validates every ReferenceRemap by re-parsing From and To. If either endpoint is malformed, construction fails with ErrInvalidRemap wrapping the endpoint ("source" or "target"), its string form, and the underlying skillref.Parse error. Remaps are build-integrity declarations, so a bad endpoint aborts resolver construction.
Source
Thrown at internal/skillref/resolver.go:48
exact map[string]Ref
}
// New validates mappings against content and returns an immutable resolver.
//
// Explicit targets are build-integrity declarations and must exist. In
// contrast, an unmapped canonical reference may be absent: presenters then
// omit the complete guidance fragment that owns it.
func New(content fs.FS, mappings []Mapping) (*Resolver, error) {
r := &Resolver{
content: content,
skills: make(map[string]Ref),
exact: make(map[string]Ref),
}
seen := make(map[string]bool, len(mappings))
for _, mapping := range mappings {
from, to := mapping.From, mapping.To
if _, err := Parse(from.String()); err != nil {
return nil, fmt.Errorf("%w: source %q: %w", ErrInvalidRemap, from.String(), err)
}
if _, err := Parse(to.String()); err != nil {
return nil, fmt.Errorf("%w: target %q: %w", ErrInvalidRemap, to.String(), err)
}
key := from.String()
if seen[key] {
return nil, fmt.Errorf("%w: source %q is mapped more than once", ErrInvalidRemap, key)
}
seen[key] = true
if from.Path == "" {
if to.Path != "" {
return nil, fmt.Errorf(
"%w: whole-skill source %q requires a bare target skill, got %q",
ErrInvalidRemap, key, to.String())
}
r.skills[from.Skill] = to
} else {View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Fix the Ref endpoint named in the message (source = From, target = To) so skillref.Parse succeeds; read the wrapped error for the specific rule broken.
- Validate endpoints with skillref.Parse / ValidSkillName when constructing the Mapping instead of after.
- Ensure whole-skill remaps use bare names on both sides (From.Path == "" requires To.Path == "").
- Check that the remap targets exist in the composed tree too — after fixing syntax, the next New failure may be a dangling target.
Example fix
// before
Mapping{From: Ref{}, To: Ref{Skill: "auth/references"}}
// after
Mapping{From: Ref{Skill: "old-auth"}, To: Ref{Skill: "auth"}} Defensive patterns
Strategy: validation
Validate before calling
for _, m := range mappings {
if _, err := skillref.Parse(m.From.String()); err != nil { return fmt.Errorf("remap source: %w", err) }
if _, err := skillref.Parse(m.To.String()); err != nil { return fmt.Errorf("remap target: %w", err) }
} Type guard
func validMapping(m skillref.Mapping) bool {
_, e1 := skillref.Parse(m.From.String())
_, e2 := skillref.Parse(m.To.String())
return e1 == nil && e2 == nil
} Try / catch
r, err := skillref.New(content, mappings)
if errors.Is(err, skillref.ErrInvalidRemap) {
return fmt.Errorf("fix ReferenceRemaps in the SkillsOverlay: %w", err)
} Prevention
- Construct Ref values explicitly (Skill plus optional Path); never pass zero-value Ref{}
- Pre-validate every Mapping endpoint with skillref.Parse before building the overlay
- Keep whole-skill remaps bare on both sides; verify remap targets exist in the composed tree
When it happens
Trigger: Calling skillref.New (directly or via skillpolicy.ResolveWithReferences) with a Mapping whose From or To Ref serializes to an invalid reference — e.g. zero-value Ref{}, skill name with slash/dot, invalid relative path, or trailing slash.
Common situations: Plugin authors hand-build Ref values with empty or wrong fields; a Remap source written as "skill/path/extra" that violates name rules; a Ref built from an unvalidated user/config string.
Related errors
- %w: source %q: %w
- %w: target %q: %w
- skill reference is empty
- %q has invalid skill name %q
- %q has an empty relative path
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/89c6f94c70811ad0.
Report an issue: GitHub.