larksuite/cli · error
multiple plugins called Restrict; only one plugin may own th
Error message
multiple plugins called Restrict; only one plugin may own the policy
What it means
ErrMultipleRestricts indicates the platform policy resolver found more than one plugin calling Restrict() during initialization. The policy can only have a single owning plugin; when distinctOwners(PluginRules) yields more than one owner, Resolve fails with this sentinel plus the conflicting owner names. It exists so the failure is explicit and classifiable (ReasonMultipleRestricts) rather than an ambiguous precedence decision.
Source
Thrown at internal/cmdpolicy/resolver.go:40
)
type ResolveSource struct {
Kind SourceKind
Name string
}
type PluginRule struct {
PluginName string
Rule *platform.Rule
}
type Sources struct {
PluginRules []PluginRule
YAMLRules []*platform.Rule
YAMLPath string
}
var ErrMultipleRestricts = errors.New("multiple plugins called Restrict; only one plugin may own the policy")
// Resolve picks by precedence: plugin > yaml > none, returning the full
// rule set the winning source contributes. Pure function; load yaml via
// LoadYAMLPolicy first. Every returned rule is validated.
//
// Multi-rule semantics (single owner): one plugin may contribute several
// rules (each a scoped grant, OR-combined by the engine), but two or more
// DISTINCT plugins contributing rules is still a configuration error --
// the resolver aborts so independent plugins cannot silently widen each
// other's policy. yaml may likewise carry several rules under "rules:".
func Resolve(s Sources) ([]*platform.Rule, ResolveSource, error) {
owners := distinctOwners(s.PluginRules)
if len(owners) > 1 {
return nil, ResolveSource{}, fmt.Errorf("%w: %v", ErrMultipleRestricts, owners)
}
if len(s.PluginRules) > 0 {
rules := make([]*platform.Rule, 0, len(s.PluginRules))View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Remove or disable one of the plugins calling Restrict so exactly one owns the policy
- Consolidate both rule sets into a single restricting plugin
- Check the plugin list/config for accidentally duplicated policy plugins
Example fix
// before
plugins := []Plugin{readonlyPlugin, companyPolicyPlugin} // both call Restrict
// after
plugins := []Plugin{companyPolicyPlugin} // single policy owner Defensive patterns
Strategy: validation
Validate before calling
owners := distinctOwners(pluginRules)
if len(owners) > 1 {
return fmt.Errorf("multiple policy plugins: %v", owners)
} Type guard
func isMultipleRestricts(err error) bool { return errors.Is(err, cmdpolicy.ErrMultipleRestricts) } Try / catch
policy, err := cmdpolicy.Resolve(sources)
if errors.Is(err, cmdpolicy.ErrMultipleRestricts) {
// inspect err text for owner list, disable one plugin
} Prevention
- Ship at most one plugin that calls Restrict
- Document policy ownership in your plugin set's manifest
- Audit installed plugins after upgrades for new Restrict callers
- Add a startup check listing which plugin owns policy
When it happens
Trigger: Loading a plugin set where two or more plugins each call cmdpolicy Restrict(); calling Resolve (or the platform guard wiring in cmd/platform_guards.go) with such a rule list.
Common situations: Installing two policy-restricting plugins (e.g. a readonly plugin plus a custom company policy plugin) that both try to own the guard policy; misconfigured plugin manifest enabling a second restrictor unintentionally.
Related errors
- %w: %v
- plugin %q rule invalid: %w
- L3: _meta.access_tokens must not be empty
- multiple plugins customized skills; only one plugin may own
- environment variable %q is not allowlisted in provider
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/af73dda5faecb026.
Report an issue: GitHub.