{"record":{"id":"d76c0f219d1ef31b","repo":"immich-app/immich","slug":"plugin-not-found","errorCode":null,"errorMessage":"Plugin not found","messagePattern":"Plugin not found","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"warning","filePath":"server/src/services/plugin.service.ts","lineNumber":25,"sourceCode":"  PluginTemplateResponseDto,\n  mapMethod,\n  mapPlugin,\n  mapTemplate,\n} from 'src/dtos/plugin.dto.js';\nimport { BaseService } from 'src/services/base.service.js';\nimport { isMethodCompatible } from 'src/utils/workflow.js';\n\n@Injectable()\nexport class PluginService extends BaseService {\n  async search(dto: PluginSearchDto): Promise<PluginResponseDto[]> {\n    const plugins = await this.pluginRepository.search(dto);\n    return plugins.map((plugin) => mapPlugin(plugin));\n  }\n\n  async get(id: string): Promise<PluginResponseDto> {\n    const plugin = await this.pluginRepository.get(id);\n    if (!plugin) {\n      throw new BadRequestException('Plugin not found');\n    }\n    return mapPlugin(plugin);\n  }\n\n  async searchMethods(dto: PluginMethodSearchDto): Promise<PluginMethodResponseDto[]> {\n    const methods = await this.pluginRepository.searchMethods(dto);\n    return methods\n      .filter((method) => !dto.trigger || isMethodCompatible(method, dto.trigger))\n      .map((method) => mapMethod(method));\n  }\n\n  async searchTemplates(): Promise<PluginTemplateResponseDto[]> {\n    const plugins = await this.pluginRepository.search();\n    return plugins.flatMap((plugin) => plugin.templates.map((template) => mapTemplate(plugin, template)));\n  }\n}\n","sourceCodeStart":7,"sourceCodeEnd":42,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/server/src/services/plugin.service.ts#L7-L42","documentation":"The plugin service's `get` method throws this when the repository returns no plugin for the given id. It is a lookup-miss surfaced as a BadRequest to indicate the caller-supplied id does not resolve to an existing plugin. It fires after the DB query completes, so the id was syntactically valid but absent.","triggerScenarios":"Calling `pluginService.get(id)` (or the corresponding GET API) with an id that does not exist in the plugin table, e.g. a stale/deleted plugin id or a wrong id copied from another environment.","commonSituations":"Frontend caches a plugin id that was later deleted; migration between environments where plugin rows differ; a typo in a hardcoded id; a plugin uninstalled by another admin session before a dependent lookup.","solutions":["Verify the plugin id exists via the plugin list/search endpoint before calling get","Re-fetch the id from the server instead of caching it client-side","Check the plugin was not deleted/uninstalled by another process","If the id should exist, inspect the pluginRepository.get query and DB connection for data issues"],"exampleFix":"// before\nconst plugin = await api.getPlugin('my-plugin'); // throws Plugin not found\n// after\nconst plugins = await api.listPlugins();\nconst plugin = plugins.find(p => p.id === 'my-plugin');\nif (!plugin) return null;","handlingStrategy":"try-catch","validationCode":"// client-side existence check\nconst exists = (await api.listPlugins()).some(p => p.id === id);\nif (!exists) throw new SkipPlugin(id);","typeGuard":"function pluginExists(p: PluginResponseDto | null | undefined): p is PluginResponseDto {\n  return p != null && typeof p.id === 'string';\n}","tryCatchPattern":"try {\n  const plugin = await pluginService.get(id);\n} catch (e) {\n  if (e instanceof BadRequestException && e.message === 'Plugin not found') {\n    return null; // treat as absent\n  }\n  throw e;\n}","preventionTips":["Resolve ids from a list/search call rather than hardcoding them","Invalidate cached plugin ids when plugins are uninstalled","Never assume an id exists across environments"],"tags":["rest","not-found","lookup"],"backgroundTag":"record-not-found","analyzedSha":"e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c","analyzedAt":"2026-09-15T07:20:19.675Z","contentChangedAt":"2026-09-15T07:20:19.675Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}