{"record":{"id":"d751f7f12c5db9d1","repo":"different-ai/openwork","slug":"plugin-not-found","errorCode":"plugin_not_found","errorMessage":"Plugin not found.","messagePattern":"Plugin not found\\.","errorType":"http","errorClass":"RemoteMcpAppError","httpStatus":404,"severity":"error","filePath":"ee/apps/den-api/src/remote-mcp-apps.ts","lineNumber":442,"sourceCode":"      csp: { connectDomains: [], resourceDomains: [], frameDomains: [], baseUriDomains: [] },\n    },\n    diagnostics: fetched.diagnostics,\n  }\n}\n\nexport async function importRemoteMcpApp(input: {\n  context: PluginArchActorContext\n  pluginId?: string\n  sourceUrl: string\n  activate?: boolean\n  requireFreshSession?: boolean\n}) {\n  let pluginId: DenTypeId<\"plugin\"> | null = null\n  if (input.pluginId) {\n    try {\n      pluginId = normalizeDenTypeId(\"plugin\", input.pluginId)\n    } catch {\n      throw new RemoteMcpAppError(404, \"plugin_not_found\", \"Plugin not found.\")\n    }\n    // Reject an unavailable target before performing any outbound download.\n    await requirePluginArchResourceRole({\n      context: input.context,\n      requireFreshSession: input.requireFreshSession,\n      resourceId: pluginId,\n      resourceKind: \"plugin\",\n      role: \"editor\",\n    })\n  }\n  const fetched = await fetchRemoteMcpApp(input.sourceUrl)\n  if (!pluginId) {\n    const plugin = await createPlugin({\n      context: input.context,\n      name: fetched.metadata.name,\n      description: fetched.metadata.description,\n      sourceRepositoryUrl: fetched.sourceUrl.length <= 1024 ? fetched.sourceUrl : null,\n    })","sourceCodeStart":424,"sourceCodeEnd":460,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-api/src/remote-mcp-apps.ts#L424-L460","documentation":"importRemoteMcpApp accepts an optional pluginId to attach the imported app to a plugin. If that id is not a valid den plugin id, normalizeDenTypeId throws and a 404 plugin_not_found is raised before any outbound download happens, so invalid targets fail fast.","triggerScenarios":"Calling importRemoteMcpApp with input.pluginId set to a value that fails plugin id normalization: a configObject id, a malformed/truncated id, or an id from a different identifier namespace.","commonSituations":"Passing the remote MCP app's configObject id instead of the plugin id; stale plugin ids after the plugin was deleted; client-side typos or slug vs id confusion in scripts.","solutions":["Pass the plugin's actual den plugin id (as returned by plugin create/list endpoints), not a configObject id.","List plugins in your organization to get a fresh valid pluginId.","Omit pluginId entirely if you do not intend to attach the app to a plugin.","Check the id is not truncated or double-encoded in your client code."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import { normalizeDenTypeId } from \"./ids.js\";\ntry { normalizeDenTypeId(\"plugin\", pluginId); }\ncatch { throw new Error(\"Invalid plugin id before importing remote MCP app\"); }","typeGuard":"function isPluginId(id: string): boolean {\n  try { normalizeDenTypeId(\"plugin\", id); return true; } catch { return false; }\n}","tryCatchPattern":"try {\n  await importRemoteMcpApp({ context, sourceUrl, pluginId });\n} catch (e) {\n  if (e instanceof RemoteMcpAppError && e.code === \"plugin_not_found\") {\n    // pluginId malformed or not a plugin id; look up the correct id and retry\n  } else throw e;\n}","preventionTips":["Pass the plugin id from plugin create/list responses, never a configObject or app id.","Validate pluginId format with normalizeDenTypeId before the call.","Omit pluginId when no plugin attachment is intended.","Refresh plugin ids after plugin deletions or environment switches."],"tags":["not-found","identifier","plugin"],"backgroundTag":"resource-not-found","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}