{"record":{"id":"f717a2503a559e18","repo":"larksuite/cli","slug":"embeddedskills-called-more-than-once-a-plugin-o","errorCode":null,"errorMessage":"EmbeddedSkills() called more than once; a plugin owns at most one SkillsOverlay","messagePattern":"EmbeddedSkills\\(\\) called more than once; a plugin owns at most one SkillsOverlay","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"extension/platform/builder.go","lineNumber":171,"sourceCode":"\n// EmbeddedSkills contributes a SkillsOverlay (see SkillsOverlay) customizing\n// the CLI's embedded skill content. It implies FailClosed: although skill\n// content is not a command-enforcement boundary, the overlay is a distribution\n// build-integrity declaration. Silently skipping it could republish host\n// defaults that the distribution explicitly removed or replaced.\n//\n// Calling FailOpen before EmbeddedSkills is allowed; EmbeddedSkills overrides\n// it to FailClosed, matching Restrict. Calling FailOpen afterward leaves an\n// invalid final state that Build rejects. A later FailClosed restores a valid\n// final state. A plugin owns at most one SkillsOverlay, so calling\n// EmbeddedSkills more than once is a build error.\nfunc (b *Builder) EmbeddedSkills(spec *SkillsOverlay) *Builder {\n\tif spec == nil {\n\t\tb.errs = append(b.errs, errors.New(\"EmbeddedSkills(nil): spec must not be nil\"))\n\t\treturn b\n\t}\n\tif b.skillsOverlay != nil {\n\t\tb.errs = append(b.errs, errors.New(\"EmbeddedSkills() called more than once; a plugin owns at most one SkillsOverlay\"))\n\t\treturn b\n\t}\n\tb.caps.FailurePolicy = FailClosed\n\tb.skillsOverlay = cloneSkillsOverlay(spec)\n\treturn b\n}\n\n// cloneSkillsOverlay snapshots the caller's spec so a later mutation of the\n// same *SkillsOverlay cannot alter the staged copy. Selection and remap slices\n// are copied; Overlay/Base are fs.FS handles retained by reference (an fs.FS is\n// a read-only view, not caller-mutable state).\nfunc cloneSkillsOverlay(spec *SkillsOverlay) *SkillsOverlay {\n\tcp := *spec\n\tcp.Allow = append([]string(nil), spec.Allow...)\n\tcp.Remove = append([]string(nil), spec.Remove...)\n\tcp.ReferenceRemaps = append([]SkillRefRemap(nil), spec.ReferenceRemaps...)\n\treturn &cp\n}","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/extension/platform/builder.go#L153-L189","documentation":"EmbeddedSkills() was called more than once on the same Builder. A plugin owns at most one SkillsOverlay, so a second call is a build error recorded in b.errs. This keeps overlay ownership unambiguous.","triggerScenarios":"Calling builder.EmbeddedSkills(spec) twice (or in a loop) on the same Builder before Build().","commonSituations":"Merging skill sets from two sources by calling EmbeddedSkills for each; copy-pasted builder chains; a helper that unconditionally adds an overlay on top of one already added.","solutions":["Merge all skills into a single *SkillsOverlay and call EmbeddedSkills once","Create a fresh Builder if you genuinely need a second, independent plugin definition","Call Build() and read the joined error to confirm which builder call sequence is at fault"],"exampleFix":"// before\nb.EmbeddedSkills(overlay1)\nb.EmbeddedSkills(overlay2) // error\n\n// after\nmerged := mergeOverlays(overlay1, overlay2)\nb.EmbeddedSkills(merged)","handlingStrategy":"validation","validationCode":"if overlayCount > 1 {\n    merged := mergeOverlays(overlays...)\n    builder.EmbeddedSkills(merged)\n} else if overlayCount == 1 {\n    builder.EmbeddedSkills(overlays[0])\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Call EmbeddedSkills exactly once per Builder; merge overlays beforehand","Wrap builder construction in a helper that centralizes the single overlay call","Search builder chains for duplicate EmbeddedSkills calls during review"],"tags":["go","plugin-builder","duplicate-call"],"backgroundTag":"duplicate-initialization","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}