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
- Read the error's second ID (previous.ModelName vs registration.ModelName) to identify the two conflicting capabilities
- Rename the duplicate capability's ID so it is unique (keep the 'plugin/frontend/' prefix convention for plugin tools)
- Remove the stale/duplicate registration from config or plugin manifest
- 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
- Namespace capability IDs by plugin name and version
- Add a uniqueness assertion in plugin manifest linting
- Deduplicate capabilities before calling buildCapabilitySet
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
- capability model name collision [%s]: %s and %s
- invalid frontend capability [%s]: %w
- capability was not exposed in this model round
- host has no public IP:
- Failed to save agent session
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/79f6a8507d1743bb.
Report an issue: GitHub.