gotify/server · error · ErrAlreadyEnabledOrDisabled
config is already enabled/disabled
Error message
config is already enabled/disabled
What it means
Sentinel error ErrAlreadyEnabledOrDisabled returned by Manager.SetPluginEnabled when the requested state change is a no-op: the plugin conf is already in the requested enabled/disabled state. It is a generic guard used by the API handlers at api/plugin.go:140 and api/plugin.go:198 to answer HTTP 400 instead of 500.
Source
Thrown at plugin/manager.go:104
if err := manager.loadPlugins(directory); err != nil {
return nil, err
}
users, err := manager.db.GetUsers()
if err != nil {
return nil, err
}
for _, user := range users {
if err := manager.initializeForUser(*user); err != nil {
return nil, err
}
}
return manager, nil
}
// ErrAlreadyEnabledOrDisabled is returned on SetPluginEnabled call when a plugin is already enabled or disabled.
var ErrAlreadyEnabledOrDisabled = errors.New("config is already enabled/disabled")
// SetPluginEnabled sets the plugins enabled state.
func (m *Manager) SetPluginEnabled(pluginID uint, enabled bool) error {
instance, err := m.Instance(pluginID)
if err != nil {
return errors.New("instance not found")
}
conf, err := m.db.GetPluginConfByID(pluginID)
if err != nil {
return err
}
if conf.Enabled == enabled {
return ErrAlreadyEnabledOrDisabled
}
m.mutex.Lock()
defer m.mutex.Unlock()View on GitHub (pinned to 14bfc25627)
Solutions
- Check current plugin state before calling SetPluginEnabled and skip redundant calls
- In the API client, treat this sentinel (errors.Is / == comparison) as an idempotent success rather than a failure
- Return 200/304-style response in the handler when the desired state already holds
Defensive patterns
Strategy: type-guard
When it happens
Trigger: Thrown at plugin/manager.go:104 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of gotify/server@14bfc25627 (2026-09-05).
Data as JSON: /api/errors/b4802956dc1e9469.
Report an issue: GitHub.