decolua/9router · error · Error

"Empty API key returned from iFlow"

Error message

"Empty API key returned from iFlow"

What it means

The iFlow user-info call succeeded but result.data contains no usable apiKey (missing, null, or whitespace-only). iFlow accounts authenticate downstream API calls with this key, so the OAuth flow aborts rather than saving a credential that cannot work.

Source

Thrown at src/lib/oauth/providers/iflow.js:70

        },
      }
    );

    if (!userInfoRes.ok) {
      const errorText = await userInfoRes.text();
      throw new Error(`Failed to fetch user info: ${errorText}`);
    }

    const result = await userInfoRes.json();
    if (!result.success) {
      throw new Error(`User info request failed: ${result.message || 'Unknown error'}`);
    }

    const userInfo = result.data || {};

    // Validate API key (critical for iFlow)
    if (!userInfo.apiKey || userInfo.apiKey.trim() === "") {
      throw new Error("Empty API key returned from iFlow");
    }

    // Validate email/phone
    const email = userInfo.email?.trim() || userInfo.phone?.trim();
    if (!email) {
      throw new Error("Missing account email/phone in user info");
    }

    return { userInfo };
  },
  mapTokens: (tokens, extra) => ({
    accessToken: tokens.access_token,
    refreshToken: tokens.refresh_token,
    expiresIn: tokens.expires_in,
    apiKey: extra?.userInfo?.apiKey,
    email: extra?.userInfo?.email || extra?.userInfo?.phone,
    displayName: extra?.userInfo?.nickname || extra?.userInfo?.name,
  }),

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Log in to the iFlow console and confirm/generate an API key for the account, then retry the OAuth flow.
  2. If data was empty entirely, dump the raw user-info JSON — a schema change (renamed field) is likely; update the lookup accordingly.
  3. Verify the account is eligible for API access in its region/plan; upgrade or switch accounts if iFlow withholds keys.
  4. Retry the flow — occasionally keys are provisioned asynchronously right after account activation.

Example fix

// before
const userInfo = result.data || {};
if (!userInfo.apiKey || userInfo.apiKey.trim() === "") {
  throw new Error("Empty API key returned from iFlow");
}
// after: distinguish missing-data vs missing-key
const userInfo = result.data;
if (!userInfo) {
  throw new Error(`iFlow user info missing data field: ${JSON.stringify(result).slice(0, 300)}`);
}
if (!userInfo.apiKey || userInfo.apiKey.trim() === "") {
  throw new Error("iFlow account has no API key provisioned — generate one in the iFlow console");
}
Defensive patterns

Strategy: validation

Validate before calling

// validate the user-info payload before/after postExchange
function hasUsableApiKey(data) {
  return typeof data === 'object' && data !== null
    && typeof data.apiKey === 'string'
    && data.apiKey.trim().length > 0;
}
// usage: if (!hasUsableApiKey(userInfo)) throw new Error('iFlow API key not provisioned');

Type guard

function isUserInfoWithApiKey(u) {
  return typeof u === 'object' && u !== null && 'apiKey' in u
    && typeof u.apiKey === 'string' && u.apiKey.trim() !== '';
}

Try / catch

try {
  const { userInfo } = await provider.postExchange(tokens);
} catch (e) {
  if (e.message === 'Empty API key returned from iFlow') {
    // actionable, user-facing: not retryable, direct to iFlow console
    return { ok: false, reason: 'no-api-key', hint: 'Generate an API key in the iFlow console, then retry login' };
  }
  throw e;
}

Prevention

When it happens

Trigger: postExchange validates userInfo = result.data || {} and throws when !userInfo.apiKey || userInfo.apiKey.trim() === '' — i.e. data is absent entirely (schema drift), or the account has no API key provisioned yet, or iFlow returned apiKey: '' for a newly registered account.

Common situations: Newly created iFlow accounts where the API key has not been generated yet; response schema change (apiKey renamed/moved out of data) so the check reads undefined; regional restrictions where iFlow declines to issue keys; result.data accidentally null so userInfo defaults to {}.

Understand the failure class

Background: "API key is required" / "API key not found" / "No API key was set": the missing-api-key error family across 16 libraries — this error's family across 16 libraries.

Related errors


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