decolua/9router · info · Error

"No JSON found in decoded code"

Error message

"No JSON found in decoded code"

What it means

cline.js first assumes the OAuth `code` callback param is itself a base64-encoded JSON blob of token data (the Cline extension-style flow). It base64-decodes the code, finds the last '}' and parses the JSON. This error is thrown when the decoded string contains no '}' — i.e. the code is not an encoded token payload but a plain authorization code. The catch block then falls back to a real HTTP token exchange, so this error is an internal branch trigger, not a user-facing failure, unless the fallback exchange also fails.

Source

Thrown at src/lib/oauth/providers/cline.js:22

  config: CLINE_CONFIG,
  flowType: "authorization_code",
  buildAuthUrl: (config, redirectUri) => {
    const params = new URLSearchParams({
      client_type: "extension",
      callback_url: redirectUri,
      redirect_uri: redirectUri,
    });
    return `${config.authorizeUrl}?${params.toString()}`;
  },
  exchangeToken: async (config, code, redirectUri) => {
    try {
      // Cline encodes token data as base64 in the code param
      let base64 = code;
      const padding = 4 - (base64.length % 4);
      if (padding !== 4) base64 += "=".repeat(padding);
      const decoded = Buffer.from(base64, "base64").toString("utf-8");
      const lastBrace = decoded.lastIndexOf("}");
      if (lastBrace === -1) throw new Error("No JSON found in decoded code");
      const tokenData = JSON.parse(decoded.substring(0, lastBrace + 1));
      return {
        access_token: tokenData.accessToken,
        refresh_token: tokenData.refreshToken,
        email: tokenData.email,
        firstName: tokenData.firstName,
        lastName: tokenData.lastName,
        expires_at: tokenData.expiresAt,
      };
    } catch (e) {
      const response = await fetch(config.tokenExchangeUrl, {
        method: "POST",
        headers: { "Content-Type": "application/json", Accept: "application/json" },
        body: JSON.stringify({ grant_type: "authorization_code", code, client_type: "extension", redirect_uri: redirectUri }),
      });
      if (!response.ok) {
        const error = await response.text();
        throw new Error(`Cline token exchange failed: ${error}`);

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. No action usually needed: the catch block automatically performs the standard Cline token exchange.
  2. If both paths fail, check the fallback error (`Cline token exchange failed: ...`) — that is the real cause.
  3. Verify the callback URL supplied the code param from Cline's authorize endpoint unmodified (not URL-decoded twice).
  4. Update CLINE_CONFIG/tokenExchangeUrl if Cline changed its extension flow.

Example fix

null
Defensive patterns

Strategy: try-catch

Validate before calling

function looksLikeBase64Json(code) {
  if (typeof code !== 'string' || !code) return false;
  let b = code;
  const pad = 4 - (b.length % 4);
  if (pad !== 4) b += '='.repeat(pad);
  try {
    return Buffer.from(b, 'base64').toString('utf-8').includes('}');
  } catch { return false; }
}
// skip the decode path when looksLikeBase64Json(code) is false

Type guard

function isEncodedTokenPayload(code) {
  if (typeof code !== 'string') return false;
  try {
    const decoded = Buffer.from(code, 'base64').toString('utf-8');
    return decoded.includes('{') && decoded.includes('}');
  } catch { return false; }
}

Try / catch

try {
  const tokens = await cline.exchangeToken(config, code, redirectUri);
  // use tokens
} catch (err) {
  if (err.message === 'No JSON found in decoded code') {
    // expected when Cline issues plain codes — fallback exchange already ran;
    // reaching here means BOTH paths failed: surface the fallback error instead
  }
  throw err;
}

Prevention

When it happens

Trigger: exchangeToken receives a plain/short authorization code (e.g. 'abc123') whose base64 decoding contains no JSON, or an empty/garbage code param from a malformed callback.

Common situations: Cline changing its callback format so codes are no longer base64 JSON, calling the flow with a manually pasted code, or a misconfigured redirect that passes error params as the code.

Related errors


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