paperclipai/paperclip · error

Invalid login

Error message

Invalid login

What it means

After loading a grok auth payload, the service probes https://api.x.ai/v1/models with the stored bearer key (redirects forbidden, 15s timeout). A non-ok response throws 'Invalid login' — the credential exists but x.ai rejected it. The outer catch converts all provider errors into an unprocessable-entity message so credential material is never leaked in error text.

Solutions

  1. Re-run the provider sign-in command to store a fresh xAI key, then retry Connect
  2. Verify the key is active and valid at console.x.ai; generate a new one if revoked
  3. Confirm the key has permission to call /v1/models (no org/scope restrictions)
  4. Check connectivity/egress to api.x.ai from the server if status is 5xx

Example fix

// before
# key revoked in xAI console; auth.json still holds old key
// after
# generate new key at console.x.ai, re-run sign-in command, retry Connect
Defensive patterns

Strategy: retry

Validate before calling

// pre-check the key yourself before connecting
const res = await fetch("https://api.x.ai/v1/models", {
  headers: { Authorization: `Bearer ${key}` }, signal: AbortSignal.timeout(15000),
});
if (!res.ok) console.error(`xAI key rejected: HTTP ${res.status} — rotate the key and re-run sign-in`);

Try / catch

try {
  await readVerifiedLocalAiCredential({ provider: "grok", loginHome });
} catch (e) {
  if (/Could not verify the local subscription/.test(String(e?.message))) {
    // invalid or unverifiable key: guide the user to regenerate and re-sign-in
    showSetupHint("Key rejected by api.x.ai; generate a new key and re-run sign-in");
  } else throw e;
}

Prevention

When it happens

Trigger: Stored xAI API key revoked or expired; key lacks access to /v1/models; x.ai returns 401/403/5xx; network/timeout treated by the catch path (surfaced as the generic unprocessable message rather than this throw, but the same Connect flow).

Common situations: Rotated the API key in the xAI console without re-running sign-in; team key deactivated; org suspended; key created with restricted scopes.

Related errors


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18). Data as JSON: /api/errors/bd0a5f37ad323349. Report an issue: GitHub.

Appendix: source

Thrown at server/src/services/local-ai-credentials.ts:54

      if (!token) throw new Error("Missing login");
      await fetchClaudeQuota(token);
      return token;
    }
    if (provider === "openai") {
      const auth = await readCodexAuthInfo(loginHome);
      if (!auth?.accessToken || !auth.refreshToken || !auth.idToken) throw new Error("Missing login");
      await fetchCodexQuota(auth.accessToken, auth.accountId);
      return JSON.stringify({ tokens: { access_token: auth.accessToken, refresh_token: auth.refreshToken, id_token: auth.idToken, account_id: auth.accountId }, last_refresh: auth.lastRefresh });
    }
    const raw = await fs.readFile(path.join(loginHome!, "auth.json"), "utf8");
    const payload = parseGrokAuthPayload(JSON.parse(raw));
    if (!payload || !hasUsableGrokAuthValue(payload.value)) throw new Error("Missing login");
    const response = await fetch("https://api.x.ai/v1/models", {
      headers: { Authorization: `Bearer ${payload.value.key}` },
      redirect: "error", signal: AbortSignal.timeout(15000),
    });
    await response.body?.cancel();
    if (!response.ok) throw new Error("Invalid login");
    return raw;
  } catch {
    // Provider/CLI errors may contain credential material; never return them.
    throw unprocessable(provider === "anthropic" && !loginHome
      ? "Could not verify the local subscription. Run claude auth login in a terminal on the machine running Paperclip, then try Connect again."
      : "Could not verify the local subscription. Run the sign-in command shown for this connection, finish signing in, then try Connect again.");
  }
}

View on GitHub (pinned to 3f1d897a7c)