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

  1. Verify the plugin instance is running: list instances from the manager and confirm the ID exists before enabling
  2. Re-instantiate or restart the plugin (e.g. via the plugin install/start flow) so Manager.Instance(id) succeeds
  3. Check manager logs for instantiation/startup failure for this plugin ID
  4. 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

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


AI-assisted analysis of gotify/server@14bfc25627 (2026-09-05). Data as JSON: /api/errors/70ab7e684bc19966. Report an issue: GitHub.