different-ai/openwork · error

Failed to load plugin contents (${membershipsResult.response

Error message

Failed to load plugin contents (${membershipsResult.response.status}).

What it means

Same fetchResolvedPlugin flow: after the plugin detail request succeeds, a non-2xx from GET /v1/plugins/:id/resolved (plugin membership/contents) throws this error with the status embedded in the fallback message. It is checked only after the plugin fetch succeeds, so the plugin itself exists but its resolved contents could not be loaded.

Source

Thrown at ee/apps/den-web/app/(den)/dashboard/_components/plugin-data.tsx:626

    case "Notification":
    case "Stop":
      return value;
    default:
      return "Notification";
  }
}

async function fetchResolvedPlugin(id: string): Promise<DenPlugin | null> {
  const [pluginResult, membershipsResult] = await Promise.all([
    requestJson(`/v1/plugins/${encodeURIComponent(id)}`, { method: "GET" }, 15000),
    requestJson(`/v1/plugins/${encodeURIComponent(id)}/resolved`, { method: "GET" }, 15000),
  ]);

  if (!pluginResult.response.ok) {
    throw new Error(getErrorMessage(pluginResult.payload, `Failed to load plugin (${pluginResult.response.status}).`));
  }
  if (!membershipsResult.response.ok) {
    throw new Error(getErrorMessage(membershipsResult.payload, `Failed to load plugin contents (${membershipsResult.response.status}).`));
  }

  const pluginItem = isRecord(pluginResult.payload) && isRecord(pluginResult.payload.item) ? pluginResult.payload.item : null;
  if (!pluginItem) {
    return null;
  }

  const pluginId = asString(pluginItem.id);
  const name = asString(pluginItem.name);
  if (!pluginId || !name) {
    return null;
  }

  const membershipItems = isRecord(membershipsResult.payload) && Array.isArray(membershipsResult.payload.items)
    ? membershipsResult.payload.items.map(parseMembershipConfigObject).filter((value): value is NonNullable<typeof value> => Boolean(value))
    : [];

  const skills = membershipItems

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Check the response status: 403 means fix org permissions for the current user (membership read access).
  2. Retry after transient 5xx; inspect Den server logs for the resolution failure.
  3. Upgrade a self-hosted Den server if /v1/plugins/{id}/resolved returns 404/405 (endpoint missing).
  4. Re-open the plugin after republishing if the contents were mid-publication.

Example fix

// before: contents error only distinguishes via status string
if (!membershipsResult.response.ok) {
  throw new Error(getErrorMessage(membershipsResult.payload, `Failed to load plugin contents (${membershipsResult.response.status}).`));
}
// after: degrade gracefully when contents cannot be read
if (!membershipsResult.response.ok) {
  if (membershipsResult.response.status === 403) {
    return buildPluginWithoutContents(pluginItem);
  }
  throw new Error(getErrorMessage(membershipsResult.payload, `Failed to load plugin contents (${membershipsResult.response.status}).`));
}
Defensive patterns

Strategy: fallback

Validate before calling

const membershipReadable = await canCurrentUser("plugin.memberships.read", orgSlug);
if (!membershipReadable) return buildPluginWithoutContents(pluginId);

Type guard

function hasItemsPayload(p: unknown): p is { items: unknown[] } {
  return typeof p === "object" && p !== null && Array.isArray((p as { items?: unknown }).items);
}

Try / catch

try {
  resolved = await requestJson(`/v1/plugins/${id}/resolved`, { method: "GET" }, 15000);
} catch {
  resolved = null; // degrade: render plugin detail without contents
}
if (!resolved?.response.ok) resolved = null;

Prevention

When it happens

Trigger: GET /v1/plugins/{id}/resolved returns 401/403 (user can see the plugin but lacks permission to list its memberships/contents), 404 (contents endpoint unavailable or version mismatch on the Den server), or 5xx during content resolution.

Common situations: A role downgraded to viewer without membership-read rights; self-hosted Den server older than the resolved-contents endpoint; transient 5xx while the server resolves many plugin memberships; the plugin just published and its contents not yet propagated.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/9773ff5780ee04cd. Report an issue: GitHub.