{"record":{"id":"130d8af56447c0d3","repo":"Molunerfinn/PicGo","slug":"plugin-not-found","errorCode":null,"errorMessage":"Plugin not found","messagePattern":"Plugin not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/renderer/store/plugins/actions.ts","lineNumber":274,"sourceCode":"      toast.success(i18n.t('PLUGIN_UNINSTALL_SUCCEED'))\n    } finally {\n      pluginStoreActions.setMutating(fullName, false)\n    }\n  },\n  async savePluginConfig (\n    fullName: string,\n    section: PluginConfigSectionType,\n    values: Record<string, unknown>\n  ) {\n    pluginStoreActions.setMutating(fullName, true)\n\n    try {\n      const installedPlugin = useAppStore.getState().pluginsInstalled.find(\n        (item) => item.fullName === fullName\n      )\n\n      if (!installedPlugin) {\n        throw new Error('Plugin not found')\n      }\n\n      const targetConfigName =\n        section === 'config'\n          ? installedPlugin.config.plugin.fullName || installedPlugin.config.plugin.name\n          : installedPlugin.config.transformer.fullName || installedPlugin.config.transformer.name\n\n      await pluginsAdapter.savePluginConfig(\n        section === 'config' ? 'plugin' : 'transformer',\n        targetConfigName,\n        values as IStringKeyMap\n      )\n      await appActions.refreshAppConfig()\n      const installedPlugins = await pluginsAdapter.getInstalledPlugins()\n      pluginStoreActions.setInstalledPlugins(installedPlugins.map(mapInstalledPluginItem))\n    } finally {\n      pluginStoreActions.setMutating(fullName, false)\n    }","sourceCodeStart":256,"sourceCodeEnd":292,"githubUrl":"https://github.com/Molunerfinn/PicGo/blob/07ec7068a5512344da093d49a8408fa63ba3421e/src/renderer/store/plugins/actions.ts#L256-L292","documentation":"savePluginConfig throws the literal 'Plugin not found' when the fullName being configured does not exist in the appStore's pluginsInstalled list. This is a client-side guard before computing the target config name — the plugin entry (with its config/transformer sections) is required to build the config payload.","triggerScenarios":"savePluginConfig called with a fullName that is not in useAppStore.getState().pluginsInstalled: stale component state after the plugin was uninstalled elsewhere, misspelled fullName, plugin list not yet hydrated (hydrateAppState not awaited), or the name includes the picgo-plugin- prefix while the stored list uses the short name.","commonSituations":"Saving a plugin settings form after the plugin was uninstalled in another window/tab; rendering config UI before the installed-plugins fetch completes; mismatch between registry fullName (picgo-plugin-foo) and the shortened stored name (foo).","solutions":["Verify the fullName matches an entry in the installed plugins list exactly (compare against mapInstalledPluginItem output).","Ensure appActions.hydrateAppState()/getInstalledPlugins completed before rendering or saving plugin config UI.","Strip or add the picgo-plugin- prefix consistently (see streamlinePluginName) when matching names.","Refresh the installed list after any install/uninstall, then retry saving the config.","Show a user-facing 'plugin not installed' toast instead of only throwing, so the dialog can close gracefully."],"exampleFix":"// before\nconst installedPlugin = useAppStore.getState().pluginsInstalled.find(\n  (item) => item.fullName === fullName\n)\nif (!installedPlugin) {\n  throw new Error('Plugin not found')\n}\n// after\nconst installedPlugin = useAppStore.getState().pluginsInstalled.find(\n  (item) => item.fullName === fullName || `picgo-plugin-${item.fullName}` === fullName\n)\nif (!installedPlugin) {\n  toast.error(i18n.t('PLUGIN_NOT_FOUND'))\n  return\n}","handlingStrategy":"type-guard","validationCode":"const installedPlugin = useAppStore.getState().pluginsInstalled.find(\n  (item) => item.fullName === fullName || `picgo-plugin-${item.fullName}` === fullName\n)\nif (!installedPlugin) {\n  toast.error(i18n.t('PLUGIN_NOT_FOUND'))\n  return\n}","typeGuard":"function findInstalledPlugin(list: IPicGoPlugin[], fullName: string): IPicGoPlugin | undefined {\n  return list.find(\n    (item) => item.fullName === fullName || item.fullName === fullName.replace(/^picgo-plugin-/, '')\n  )\n}","tryCatchPattern":"try {\n  await pluginStoreActions.savePluginConfig(fullName, section, data)\n} catch (e) {\n  if (e instanceof Error && e.message === 'Plugin not found') {\n    toast.error(i18n.t('PLUGIN_NOT_FOUND'))\n    return\n  }\n  throw e\n}","preventionTips":["Await appActions.hydrateAppState() before rendering plugin config forms so pluginsInstalled is populated.","Normalize fullName with streamlinePluginName when matching stored entries.","Close/disable config dialogs when the underlying plugin is uninstalled.","Refresh the installed list after install/uninstall flows before allowing config saves."],"tags":["plugin","state","validation","zustand"],"backgroundTag":"plugin-not-found","analyzedSha":"07ec7068a5512344da093d49a8408fa63ba3421e","analyzedAt":"2026-08-30T01:45:22.289Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}