VIEWPORT
Troubleshooting

Tenant context errors

428, 409, 403 from tenant endpoints. Switching orgs feels stuck. Web app shows Forbidden after creating an org.

The platform uses explicit tenant context for every tenant-scoped request. Errors here are specific and recoverable.

The status codes

CodeNameMeaning
428tenant_context_requiredYou hit a tenant endpoint without X-Viewport-Organization and no route binding.
422invalid_tenant_contextThe org id format is malformed (not a ULID).
403tenant_forbiddenThe org id is valid but you're not a member.
409tenant_context_mismatchThe route's workspace and the header's workspace disagree.

The web app should not surface these to end users. They should never happen with normal navigation. If you see one, something's wrong.

Symptom: "Forbidden" banner after creating a new org

Created a new org, switched into it, opened /workflows or /plans, banner says "Forbidden."

Cause: stale tenant context. The frontend switched the active org but a cached query fired with the old org id.

Fix:

1. Open dev tools → Application → Local storage
2. Find activeOrganizationId, delete it
3. Reload

This forces a fresh org-selection round. If it persists, the membership row for your owner role may not have been created. Tell us with the workspace id from the URL.

Symptom: org switcher shows old org name

You switched to org B, but the chip in the top-left still says "Org A."

Cause: race between the API switch endpoint and the local store update.

Fix: reload. The store re-fetches from /api/me on load and picks up the actual active org.

Symptom: notifications from an org you don't recognize

Phone push from an org you don't remember being a member of.

Cause: most likely you were invited and accepted at some point. Less likely: a security issue.

Fix:

  1. Open the app. Click the org switcher. Pick the unfamiliar org.
  2. Go to Members → your row. Confirm your role and the org name.
  3. If you don't want to be a member, leave: Members → row → Leave organization.

If the org and inviter look suspicious, report it.

Symptom: API call from your script returns 428

You wrote a script using a personal access token:

curl -H "Authorization: Bearer $VIEWPORT_TOKEN" https://api.getviewport.com/api/plans
# {"error":{"code":"tenant_context_required"}}

Cause: user-scoped tokens require explicit org context per request.

Fix: add the header.

curl -H "Authorization: Bearer $VIEWPORT_TOKEN" \
     -H "X-Viewport-Organization: $WORKSPACE_ID" \
     https://api.getviewport.com/api/plans

For CI / integrations that always run against one org, create an org-bound token instead. It has the org baked in and you don't need the header. See Reference: API. Auth.

Symptom: route + header mismatch (409)

GET /api/workspaces/01J7A.../plans
X-Viewport-Organization: 01J7B...

Cause: the URL says org A, the header says org B. Platform refuses to silently choose.

Fix: pick one. If the URL is authoritative (route binding), drop the header. If the header is authoritative, drop the workspace from the URL and use the clean route /api/plans.

Where to go next

On this page