{"record":{"id":"61e63ab40bcc433e","repo":"different-ai/openwork","slug":"failed-to-load-plugin-pluginresult-response-sta","errorCode":null,"errorMessage":"Failed to load plugin (${pluginResult.response.status}).","messagePattern":"Failed to load plugin \\((.+?)\\)\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ee/apps/den-web/app/(den)/dashboard/_components/plugin-data.tsx","lineNumber":623,"sourceCode":"    case \"SessionStart\":\n    case \"SessionEnd\":\n    case \"UserPromptSubmit\":\n    case \"Notification\":\n    case \"Stop\":\n      return value;\n    default:\n      return \"Notification\";\n  }\n}\n\nasync function fetchResolvedPlugin(id: string): Promise<DenPlugin | null> {\n  const [pluginResult, membershipsResult] = await Promise.all([\n    requestJson(`/v1/plugins/${encodeURIComponent(id)}`, { method: \"GET\" }, 15000),\n    requestJson(`/v1/plugins/${encodeURIComponent(id)}/resolved`, { method: \"GET\" }, 15000),\n  ]);\n\n  if (!pluginResult.response.ok) {\n    throw new Error(getErrorMessage(pluginResult.payload, `Failed to load plugin (${pluginResult.response.status}).`));\n  }\n  if (!membershipsResult.response.ok) {\n    throw new Error(getErrorMessage(membershipsResult.payload, `Failed to load plugin contents (${membershipsResult.response.status}).`));\n  }\n\n  const pluginItem = isRecord(pluginResult.payload) && isRecord(pluginResult.payload.item) ? pluginResult.payload.item : null;\n  if (!pluginItem) {\n    return null;\n  }\n\n  const pluginId = asString(pluginItem.id);\n  const name = asString(pluginItem.name);\n  if (!pluginId || !name) {\n    return null;\n  }\n\n  const membershipItems = isRecord(membershipsResult.payload) && Array.isArray(membershipsResult.payload.items)\n    ? membershipsResult.payload.items.map(parseMembershipConfigObject).filter((value): value is NonNullable<typeof value> => Boolean(value))","sourceCodeStart":605,"sourceCodeEnd":641,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-web/app/(den)/dashboard/_components/plugin-data.tsx#L605-L641","documentation":"fetchResolvedPlugin issues two parallel GETs (/v1/plugins/:id and /v1/plugins/:id/resolved). If the plugin-detail request returns a non-2xx status it throws this error, using the server's error message from the payload when available. Callers (usePlugin, plugins queries) surface it via TanStack Query.","triggerScenarios":"GET /v1/plugins/{id} returns 401/403 (session expired, no permission on the plugin's org), 404 (plugin deleted or id mistyped), or 5xx from the Den server. Note both requests run unconditionally; the plugin fetch is checked first.","commonSituations":"Opening a bookmarked plugin route after the plugin was unpublished; stale pluginQueryKeys cache pointing at a deleted id; den-web pointed at a Den server in a different org/environment; server restart or migration in progress causing 5xx.","solutions":["Re-authenticate if status is 401/403; verify the session cookie is present in the failing request.","Confirm the plugin id via the plugins list (GET /v1/plugins?status=active) and correct the URL/route.","If the plugin was deleted, clear the stale link/query cache and navigate back to the plugin list.","Check Den server logs/health when the status is 5xx; retry after the server recovers."],"exampleFix":"// before: both requests fire even if the first fails\nconst [pluginResult, membershipsResult] = await Promise.all([...]);\nif (!pluginResult.response.ok) {\n  throw new Error(getErrorMessage(pluginResult.payload, `Failed to load plugin (${pluginResult.response.status}).`));\n}\n// after: short-circuit so a 404 doesn't also burn the memberships call\nconst pluginResult = await requestJson(`/v1/plugins/${encodeURIComponent(id)}`, { method: \"GET\" }, 15000);\nif (!pluginResult.response.ok) {\n  throw new Error(getErrorMessage(pluginResult.payload, `Failed to load plugin (${pluginResult.response.status}).`));\n}\nconst membershipsResult = await requestJson(`/v1/plugins/${encodeURIComponent(id)}/resolved`, { method: \"GET\" }, 15000);","handlingStrategy":"try-catch","validationCode":"const idOk = typeof id === \"string\" && id.length > 0;\nconst sessionOk = await ensureSession(); // redirect on 401 before issuing the request\nif (!idOk || !sessionOk) return null;","typeGuard":"function isPluginPayload(p: unknown): p is { item: Record<string, unknown> } {\n  return typeof p === \"object\" && p !== null && isRecord((p as { item?: unknown }).item);\n}","tryCatchPattern":"try {\n  const plugin = await fetchResolvedPlugin(id);\n} catch (err) {\n  const m = err instanceof Error ? err.message : \"\";\n  if (m.includes(\"(404)\")) { notFound(); return null; }\n  if (m.includes(\"(401)\") || m.includes(\"(403)\")) { await redirectToSignIn(); return null; }\n  showToast(\"Failed to load plugin; please retry.\");\n}","preventionTips":["Short-circuit the second request when the first fails to avoid wasted calls and clearer errors.","Treat 404 as 'plugin gone': clear stale cached routes and query keys pointing at deleted ids.","Keep den-web and Den server versions in lockstep; version-gate new endpoints.","Use TanStack Query's error state to render a retry button instead of crashing the route."],"tags":["http","api-client","den-web","plugin"],"backgroundTag":"http-request-failed-with-status","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}