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

  1. 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.
  2. Validate endpoints with skillref.Parse / ValidSkillName when constructing the Mapping instead of after.
  3. Ensure whole-skill remaps use bare names on both sides (From.Path == "" requires To.Path == "").
  4. 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

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


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