Ask a host that exists for the organization ?org= names

Fixkamo-internal
Shipped
August 26, 2026 at 8:42 PM UTC
Author
kamo
Commit
9cf27f5

A new organization was created with its logo, colours and three backgrounds. All of it provisioned correctly into public/wienerschnitzel/ — 15 objects, the right hex values in globals.css, config.json naming three backgrounds. The tab still opened wearing Kamo's branding. The reason was here, in the pod log: [org GET] alias=wienerschnitzel **************** **************** [org fetch] GET **************** [retry] org err='fetch failed' isAbort=false willRetryIn=250ms [retry] org failed after 804ms attempts=3 [TypeError: fetch failed] [org GET] done status=200 features=10 This route built its upstream base as `api.<path segment>`. That worked while every segment was a hostname; `?org=` carries an organization REFERENCE now — an id or a web alias — so it asked a host that does not exist. Three things, each of which was independently enough to cause this: - The API host comes from the host THIS request arrived on. The browser already resolved internal.<apex> to get here, so api.<same apex> is known to exist whatever the reference names. It also closes a hole that only became reachable once the reference stopped being a hostname: a crafted ?org= chose which host this server sent the caller's session cookie to. - A reference goes to /org/ref, a hostname to /org/domain. Only the former can answer for an organization with no host, which is most of them now. - A failed lookup answers 404, not 200 with a fabricated KamoCRM record. That fallback — right id, isTopLevel, ten features — is why the shell could not tell "this is your organization" from "I could not reach the server", and why it treated the platform as the tab's NAMED tenant. OrgUrlSync would then have pinned that answer into the URL for every later request from the tab. fetchOrganization already handles a 404: it falls back to the host and records viaRef=false, so the fallback stays untrusted, which is the whole point. The routing logic moved to app/lib so it can actually be tested — app/api/** is not in vitest's include allowlist, so a test beside the route would have passed by never running.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing