decolua/9router · error · Error

Zed did not return an LLM token

Error message

Zed did not return an LLM token

What it means

fetchZedLlmToken POSTs to Zed's LLM-token endpoint with the organization id and extracts the token from the response, accepting `token` as a string, or as an object/array with `token[0]` or `token.value`. If none of these shapes yield a non-empty token it throws "Zed did not return an LLM token".

Source

Thrown at open-sse/shared/zedAuth.js:286

    "Content-Type": "application/json",
    Accept: "application/json",
    Authorization: buildZedUserAuthHeader(credentials),
  };
  const systemId = getSystemId(credentials);
  if (systemId) headers[ZED_HEADERS.systemId] = systemId;

  const data = await fetchJson(
    zedUrl(config, "cloudBaseUrl", "/client/llm_tokens", ZED_CLOUD_BASE_URL),
    {
      method: "POST",
      headers,
      body: JSON.stringify({ organization_id: organizationId }),
      signal: options.signal ?? undefined,
    },
  );
  const token =
    typeof data?.token === "string" ? data.token : data?.token?.[0] || data?.token?.value;
  if (!token) throw new Error("Zed did not return an LLM token");
  llmTokenCache.set(cacheKey, { token, expiresAt: Date.now() + LLM_TOKEN_TTL_MS });
  return token;
}

export function shouldRefreshZedLlmToken(response) {
  return (
    response?.status === 401 ||
    !!response?.headers?.has?.(ZED_HEADERS.expiredToken) ||
    !!response?.headers?.has?.(ZED_HEADERS.outdatedToken)
  );
}

export async function zedLlmFetch(credentials, path, options = {}) {
  const config = options.config || {};
  const url = zedUrl(config, "llmBaseUrl", path, ZED_LLM_BASE_URL);
  const buildRequest = async (forceRefresh) => {
    const token = await fetchZedLlmToken(credentials, { ...options, forceRefresh });
    return proxyAwareFetch(url, {

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Log the raw response body and check which shape `token` actually has; if it moved to a new key, adjust the extraction.
  2. Confirm the selected organization has LLM/active-seat access on Zed cloud; try another organizationId.
  3. Re-authenticate (forceRefresh or new sign-in) — an expired session can yield an empty success response.
  4. Check the response isn't an HTML/error page being JSON-parsed into {raw: text}; inspect Content-Type.

Example fix

// before
const data = { token: null }; // server returned empty
if (!token) throw ...
// after — verify upstream entitlement, or extract from alternate shape:
const token = data?.token?.value || data?.token?.[0] || data?.llm_token;
Defensive patterns

Strategy: fallback

Validate before calling

// can't validate pre-call; validate post-call instead:
if (res.ok) {
  const data = await res.json();
  const token = data?.token?.value || (Array.isArray(data?.token) ? data.token[0] : data?.token) || data?.llm_token;
  if (!token) throw new Error(`Unexpected LLM token payload: ${JSON.stringify(data).slice(0, 200)}`);
}

Type guard

const hasLlmToken = (d) => typeof d?.token === "string"
  || (Array.isArray(d?.token) && typeof d.token[0] === "string")
  || typeof d?.token?.value === "string" || typeof d?.llm_token === "string";

Try / catch

try {
  const token = await fetchZedLlmToken(credentials, { organizationId });
} catch (e) {
  if (e.message === "Zed did not return an LLM token") {
    // check org entitlement / forceRefresh / inspect raw body, then retry once
  } else throw e;
}

Prevention

When it happens

Trigger: The Zed LLM-token endpoint responds 200 but with an empty/malformed body — e.g. `{"token":[]}`, `{}`, or a body whose `token` field is null — typically when the org has no LLM access or the endpoint contract changed.

Common situations: Organization lacks LLM entitlement/seat; Zed API version changed the response shape (token now under a different key); proxy or captive portal returned a 200 HTML page parsed as {raw:...}.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/7e7c08133af4500c. Report an issue: GitHub.