larksuite/cli · error
EmbeddedSkills(nil): spec must not be nil
Error message
EmbeddedSkills(nil): spec must not be nil
What it means
EmbeddedSkills() was called with a nil *SkillsOverlay. The builder rejects nil specs up front and records the error for Build(). A nil overlay carries no skills to embed, so it is treated as a programming mistake rather than a no-op.
Source
Thrown at extension/platform/builder.go:167
cp.Identities = append([]Identity(nil), rule.Identities...)
b.rules = append(b.rules, &cp)
return b
}
// EmbeddedSkills contributes a SkillsOverlay (see SkillsOverlay) customizing
// the CLI's embedded skill content. It implies FailClosed: although skill
// content is not a command-enforcement boundary, the overlay is a distribution
// build-integrity declaration. Silently skipping it could republish host
// defaults that the distribution explicitly removed or replaced.
//
// Calling FailOpen before EmbeddedSkills is allowed; EmbeddedSkills overrides
// it to FailClosed, matching Restrict. Calling FailOpen afterward leaves an
// invalid final state that Build rejects. A later FailClosed restores a valid
// final state. A plugin owns at most one SkillsOverlay, so calling
// EmbeddedSkills more than once is a build error.
func (b *Builder) EmbeddedSkills(spec *SkillsOverlay) *Builder {
if spec == nil {
b.errs = append(b.errs, errors.New("EmbeddedSkills(nil): spec must not be nil"))
return b
}
if b.skillsOverlay != nil {
b.errs = append(b.errs, errors.New("EmbeddedSkills() called more than once; a plugin owns at most one SkillsOverlay"))
return b
}
b.caps.FailurePolicy = FailClosed
b.skillsOverlay = cloneSkillsOverlay(spec)
return b
}
// cloneSkillsOverlay snapshots the caller's spec so a later mutation of the
// same *SkillsOverlay cannot alter the staged copy. Selection and remap slices
// are copied; Overlay/Base are fs.FS handles retained by reference (an fs.FS is
// a read-only view, not caller-mutable state).
func cloneSkillsOverlay(spec *SkillsOverlay) *SkillsOverlay {
cp := *spec
cp.Allow = append([]string(nil), spec.Allow...)View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Build a valid *SkillsOverlay (with at least the required skills entries) before calling EmbeddedSkills
- Skip the EmbeddedSkills call if the plugin has no overlay to ship
- Call Build() to surface all accumulated builder errors and fix the nil input
Example fix
// before
var overlay *SkillsOverlay
b.EmbeddedSkills(overlay)
// after
if overlay != nil {
b = b.EmbeddedSkills(overlay)
} Defensive patterns
Strategy: validation
Validate before calling
if spec == nil {
return nil, fmt.Errorf("cannot build plugin: skills overlay is nil")
}
b := builder.EmbeddedSkills(spec) Type guard
func hasOverlay(s *SkillsOverlay) bool { return s != nil } Prevention
- Load and validate the SkillsOverlay before building; fail fast if the loader returns nil
- Treat nil overlay as 'no overlay' and omit the EmbeddedSkills call
- Keep overlay loading and plugin building in one code path so nil cannot slip through
When it happens
Trigger: Calling builder.EmbeddedSkills(nil), e.g. when the overlay is produced conditionally or loaded from a source that returned nil on failure.
Common situations: Skill overlay file missing or failed to parse so the loader returned nil; a struct field of type *SkillsOverlay left unset; refactor that made overlay construction conditional.
Related errors
- Restrict(nil): rule must not be nil
- EmbeddedSkills() called more than once; a plugin owns at mos
- Restrict() requires FailClosed; do not call FailOpen() after
- EmbeddedSkills() requires FailClosed; do not call FailOpen()
- Invalid column: {column!r}
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/851715cea58b0eed.
Report an issue: GitHub.