siyuan-note/siyuan · error

capability ID collision [%s]: %s and %s

Error message

capability ID collision [%s]: %s and %s

What it means

The capability set's add method rejects a registration whose capability ID is already taken by an earlier registration. Both duplicate and original ModelNames are reported so the caller can see which two capabilities clash. IDs must be unique across all registered capabilities (native and plugin).

Source

Thrown at kernel/agent/capability.go:298

			return nil, err
		}
	}

	sort.Slice(set.definitions, func(i, j int) bool {
		return set.definitions[i].Function.Name < set.definitions[j].Function.Name
	})
	return set, nil
}

func (set *capabilitySet) add(registration *capabilityRegistration) error {
	if set.registrations == nil {
		set.registrations = map[string]*capabilityRegistration{}
	}
	if set.ids == nil {
		set.ids = map[string]*capabilityRegistration{}
	}
	if previous := set.ids[registration.ID]; previous != nil {
		return fmt.Errorf("capability ID collision [%s]: %s and %s",
			registration.ID, previous.ModelName, registration.ModelName)
	}
	if previous := set.registrations[registration.ModelName]; previous != nil {
		return fmt.Errorf("capability model name collision [%s]: %s and %s",
			registration.ModelName, previous.ID, registration.ID)
	}
	set.ids[registration.ID] = registration
	set.registrations[registration.ModelName] = registration
	set.definitions = append(set.definitions, openai.Tool{
		Type: openai.ToolTypeFunction,
		Function: &openai.FunctionDefinition{
			Name:        registration.ModelName,
			Description: registration.Description,
			Parameters:  convertSchema(registration.InputSchema),
		},
	})
	return nil
}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Read the error's second ID (previous.ModelName vs registration.ModelName) to identify the two conflicting capabilities
  2. Rename the duplicate capability's ID so it is unique (keep the 'plugin/frontend/' prefix convention for plugin tools)
  3. Remove the stale/duplicate registration from config or plugin manifest
  4. If a plugin is at fault, update it to a version with unique IDs

Example fix

// before
cap1.ID = "plugin/frontend/search"; cap2.ID = "plugin/frontend/search"
// after
cap2.ID = "plugin/frontend/search2"
Defensive patterns

Strategy: validation

Validate before calling

seen := map[string]bool{}
for _, c := range capabilities { if seen[c.ID] { return fmt.Errorf("duplicate capability ID %s", c.ID) }; seen[c.ID] = true }

Try / catch

if err := set.Add(reg); err != nil { if strings.Contains(err.Error(), "ID collision") { log.Printf("skipping duplicate capability: %v", err); return nil }; return err }

Prevention

When it happens

Trigger: Calling add (via buildCapabilitySet or direct registration) with two capabilities that both declare the same registration.ID, e.g. a plugin capability whose ID collides with a native one or another plugin instance.

Common situations: Two plugin versions or two plugins register the same 'plugin/frontend/<name>' ID; a config lists the same capability twice; a native tool ID was copied into a custom registration; renaming a tool but forgetting to change its ID.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/79f6a8507d1743bb. Report an issue: GitHub.