decolua/9router · error

Missing access_token / accessToken

Error message

Missing access_token / accessToken

What it means

For each grok-cli import item the route resolves accessToken from access_token or accessToken (snake_case preferred). If neither is present as a non-empty string, it throws 'Missing access_token / accessToken'. Unlike codex import, both key spellings are accepted here.

Source

Thrown at src/app/api/oauth/grok-cli/bulk-import/route.js:67

  const results = [];
  let success = 0;
  let failed = 0;

  for (let i = 0; i < accounts.length; i++) {
    const raw = accounts[i];
    try {
      if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
        throw new Error("Item is not an object");
      }

      const accessToken = raw.access_token || raw.accessToken;
      const refreshToken = raw.refresh_token || raw.refreshToken || null;
      const idToken = raw.id_token || raw.idToken || null;
      let email = raw.email || null;

      if (!accessToken || typeof accessToken !== "string") {
        throw new Error("Missing access_token / accessToken");
      }

      if (!email) {
        email =
          decodeXaiIdTokenEmail(idToken) ||
          extractEmailFromAccessToken(accessToken) ||
          null;
      }

      let expiresAt = raw.expires_at || raw.expiresAt || null;
      const expiresIn = raw.expires_in || raw.expiresIn;
      if (!expiresAt && typeof expiresIn === "number" && expiresIn > 0) {
        expiresAt = new Date(Date.now() + expiresIn * 1000).toISOString();
      }

      const psd = {
        authMethod: "device_code",
        ...(idToken ? { idToken } : {}),

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Rename the token field to access_token or accessToken in each item.
  2. Check the value is a non-empty string, not null or "".
  3. Re-export from grok-cli (its auth file stores access_token) including the token field.

Example fix

// before
{ "accounts": [{ "token": "abc", "refresh_token": "r1" }] }
// after
{ "accounts": [{ "access_token": "abc", "refresh_token": "r1" }] }
Defensive patterns

Strategy: validation

Validate before calling

for (const a of accounts) {
  const tok = a?.access_token ?? a?.accessToken;
  if (!tok || typeof tok !== "string") {
    throw new Error("item missing access_token/accessToken");
  }
}

Type guard

const hasGrokToken = (x) => {
  const t = x?.access_token ?? x?.accessToken;
  return typeof t === "string" && t.length > 0;
};

Try / catch

try {
  await grokBulkImport(accounts);
} catch (e) {
  if (e.message.includes("Missing access_token")) {
    console.error("Rename token fields to access_token and resend");
  } else throw e;
}

Prevention

When it happens

Trigger: An accounts[] item whose only token field is named something else (e.g. token, key, apiKey), or where access_token is null/empty/non-string.

Common situations: Export from a provider that names the field token or api_key, a redacted export with access_token: "", or pasting only refresh_token / id_token entries.

Related errors


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