larksuite/cli · error · ErrMultipleRestricts
%w: %v
Error message
%w: %v
What it means
cmdpolicy.Resolve returns this error, wrapping ErrMultipleRestricts, when rules arrive from more than one DISTINCT plugin. Independent plugins cannot silently widen each other's policy, so the resolver deliberately aborts instead of merging. Note: multiple rules from a single plugin are fine; only multiple distinct plugin owners conflict.
Source
Thrown at internal/cmdpolicy/resolver.go:54
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))
for _, pr := range s.PluginRules {
if err := ValidateRule(pr.Rule); err != nil {
return nil, ResolveSource{}, fmt.Errorf("plugin %q rule invalid: %w", pr.PluginName, err)
}
rules = append(rules, pr.Rule)
}
return rules, ResolveSource{Kind: SourcePlugin, Name: owners[0]}, nil
}
if len(s.YAMLRules) > 0 {
for _, r := range s.YAMLRules {
if err := ValidateRule(r); err != nil {
return nil, ResolveSource{}, fmt.Errorf("policy yaml %q: %w", s.YAMLPath, err)
}View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Remove or disable all but one plugin that contributes policy rules
- Consolidate the restrict rules of the plugins into a single plugin's rule set
- Move shared restrictions into the policy YAML (s.YAMLRules) instead of a second plugin, since a single YAML source is allowed alongside one plugin
- Check plugin registration/config to find the conflicting plugin names listed in the error
Example fix
// before: two plugins register rules
policy.Resolve(cmdpolicy.Sources{PluginRules: rulesFromPluginA + rulesFromPluginB})
// after: single plugin owner (or move extra rules to YAML)
policy.Resolve(cmdpolicy.Sources{PluginRules: rulesFromPluginA, YAMLRules: yamlRules, YAMLPath: "policy.yaml"}) Defensive patterns
Strategy: validation
Validate before calling
owners := map[string]bool{}
for _, pr := range pluginRules { owners[pr.PluginName] = true }
if len(owners) > 1 {
return fmt.Errorf("refusing to resolve: multiple policy plugins: %v", owners)
} Prevention
- Enable at most one plugin that contributes policy rules
- Move shared restrictions into the policy YAML instead of a second plugin
- Audit installed plugins for policy contributors before composition
- Treat multiple restrict sources as a configuration error in your tooling
When it happens
Trigger: Applying user policy pruning where two or more different plugins each contributed PluginRules entries to Sources — e.g. loading several plugins that both register restrict rules.
Common situations: Installing multiple policy-enforcing plugins side by side, upgrading one plugin while an old policy plugin remains enabled, or composing plugin sets from different sources that both constrain commands.
Related errors
- multiple plugins called Restrict; only one plugin may own th
- plugin %q rule invalid: %w
- Invalid column: {column!r}
- Invalid column index: {index}
- anchor outside sheet: {position!r}
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/43e52f33c5b12d1e.
Report an issue: GitHub.