Error on every page navigation -- v3.0.0/v3.0.1 Commercial self-hosted (free tier, 12 seats)

After upgrading to v3.0.0/v3.0.1 Commercial (free 12-seat tier, no paid license), every workspace page navigation triggers the error boundary. Reloading the page recovers, but it is a very annoying step to click “Reload” whenever navigating anywhere.

Error screeen:

From the browser console, the issue seems to be with the teamspaces endpoint:

Request URL <DOMAIN>/api/workspaces/cogscai/teamspaces/
Request Method GET
Status Code 402 Payment Required

This makes Plane near unusable for us. Please assist with a fix. Thanks.


Follow-up with diagnostics.

The 402 response itself appears to be correct behavior. Per your own docs:

So a free-tier workspace receiving 402 from /api/workspaces/<slug>/teamspaces/ is the paywall working as designed. Our backend checks support this: the license activates and verifies successfully, workspace sync returns 200, GET /api/payments/workspaces/<slug>/flags/ returns {} (correct for a free-tier workspace), and all other API endpoints return 200/201.

The bug is that the frontend crashes on this legitimate 402. Console trace from the error page:

GET /api/workspaces/cogscai/teamspaces/ 402 (Payment Required)
Failed to fetch teamspaces {status: 402, ...}

TypeError: n.find is not a function
    at store-context-BjKUlH_5.js:746:704160
    at by (mobxreact.esm-*.js)            <- mobx computed
    at sidebar-wrapper-*.js
    at e.useMemo

React Router caught the following error during render
TypeError: n.find is not a function

Observed sequence on every workspace page navigation (client-side, e.g. sidebar click):

  1. client-bootstrap calls fetchTeamspaces(), which GETs /api/workspaces/<slug>/teamspaces/
  2. API returns 402
  3. The store logs “Failed to fetch teamspaces”, leaving the teamspaces observable in a non-array state
  4. A MobX computed used by the sidebar calls .find() on it and throws
  5. The React Router error boundary catches the throw and replaces the entire page

Clicking the error boundary’s Reload button (a full page reload) recovers the page. The crash recurs on the next client-side navigation.

Expected behavior: the frontend should not fetch /teamspaces/ for a workspace without the teamspace entitlement — or, defensively, the store should fall back to an empty array on fetch failure and the computed should guard the .find() call. A 402 from a paywalled endpoint should not take down the whole page.

We are on Commercial v3.0.1 (also reproduced on v3.0.0), self-hosted on Kubernetes via the Helm chart, free 12-seat tier. Happy to provide further logs or traces if useful.

Hi @staples-hyken, it looks like your API isn’t running correctly.

Could you check if the migrator job completed successfully (exit code 0) and whether the API container is running? If the API container isn’t running, please share its logs so we can help debug the issue further.

I was wrong about the whole teamspaces theory.

I fixed the issue by enabling the silo pod for our deployment. We previously had it disabled because our deployment is rather resource constrained and we don’t use any of the integrations that require silo. I guess v3 introduced some fetches/calls that call silo endpoints unconditionally, even when disabled in the Helm chart? My agent’s guess on the flow causing the error is beyond me, but I’ve pasted it below in case it is helpful:

Mechanism: with silo disabled, /silo/ has no Ingress rule and falls through to the / rule → plane-web, whose nginx returns 200 text/html (SPA index.html) for the API path. Axios resolves, the HTML string lands in the userConnections MobX store, and a sidebar computed (getIsUserConnected, new in v3) calls .find() on it → TypeError → error boundary. v2.5.3 only fetched connections from the integrations settings page, so silo-less installs were safe before v3.
Two upstream asks: (1) the frontend should validate API responses before writing them to stores — a 200 text/html fallback shouldn’t poison client state; (2) the chart shouldn’t route /silo/ to the SPA catch-all when silo.enabled: false.