gotify/server · error
plugin instance not found
Error message
plugin instance not found
What it means
This 404 is returned by the plugin-enable endpoint after the plugin configuration was already verified to exist and be owned by the caller. It means Manager.Instance(id) failed to return a running plugin instance — i.e. the plugin binary/instance is not currently instantiated in the plugin manager, so it cannot be enabled. It is distinct from 'unknown plugin', which fires when the DB config is missing or the caller is not the owner.
Source
Thrown at api/plugin.go:137
// schema:
// $ref: "#/definitions/Error"
// 500:
// description: Internal Server Error
// schema:
// $ref: "#/definitions/Error"
func (c *PluginAPI) EnablePlugin(ctx *gin.Context) {
withID(ctx, "id", func(id uint) {
conf, err := c.DB.GetPluginConfByID(id)
if success := successOrAbort(ctx, 500, err); !success {
return
}
if conf == nil || !isPluginOwner(ctx, conf) {
ctx.AbortWithError(404, errors.New("unknown plugin"))
return
}
_, err = c.Manager.Instance(id)
if err != nil {
ctx.AbortWithError(404, errors.New("plugin instance not found"))
return
}
if err := c.Manager.SetPluginEnabled(id, true); err == plugin.ErrAlreadyEnabledOrDisabled {
ctx.AbortWithError(400, err)
} else if err != nil {
ctx.AbortWithError(500, err)
}
})
}
// DisablePlugin disables a plugin.
// swagger:operation POST /plugin/{id}/disable plugin disablePlugin
//
// Disable a plugin.
//
// ---
// consumes: [application/json]
// produces: [application/json]View on GitHub (pinned to 14bfc25627)
Solutions
- Verify the plugin instance is running: list instances from the manager and confirm the ID exists before enabling
- Re-instantiate or restart the plugin (e.g. via the plugin install/start flow) so Manager.Instance(id) succeeds
- Check manager logs for instantiation/startup failure for this plugin ID
- If the DB config is stale, delete the plugin config and re-create it
Example fix
// before
_, err = c.Manager.Instance(id)
if err != nil {
ctx.AbortWithError(404, errors.New("plugin instance not found"))
return
}
// after
_, err = c.Manager.Instance(id)
if err != nil {
if errors.Is(err, plugin.ErrNotRunning) {
ctx.AbortWithError(409, errors.New("plugin is configured but not running; start it first"))
} else {
ctx.AbortWithError(404, errors.New("plugin instance not found"))
}
return
} Defensive patterns
Strategy: validation
Validate before calling
resp, err := client.Get(baseURL + "/api/plugins")
if err != nil { return err }
var plugins []Plugin
json.NewDecoder(resp.Body).Decode(&plugins)
for _, p := range plugins {
if p.ID == targetID { /* instance should be resolvable */ return nil }
}
return fmt.Errorf("plugin %d not running; cannot enable", targetID) Prevention
- List running plugin instances before enable/disable calls
- After manager restarts, re-check instance availability before mutating plugin state
- Alert on plugin crash events so state is known before API calls
- Delete orphaned plugin configs whose instances no longer exist
When it happens
Trigger: PATCH/POST to the enable-plugin endpoint with a valid, owned plugin ID whose instance cannot be resolved by Manager.Instance(id) (plugin process not running, not yet instantiated, or crashed).
Common situations: Plugin was deleted from the runtime but its DB config row still exists; plugin failed to start after a version upgrade; manager restarted and the plugin was not re-instantiated; stale UI cache pointing at a plugin whose instance was torn down.
Related errors
- cannot delete internal application
- file with key 'file' must be present
- invalid file extension
- client not found
- application does not exist
AI-assisted analysis of gotify/server@14bfc25627 (2026-09-05).
Data as JSON: /api/errors/70ab7e684bc19966.
Report an issue: GitHub.