yikart/AiToEarn · warning · BadRequestException

状态数据不完整

Error message

状态数据不完整

What it means

After finding state data in Redis, handleAuthorizationCallback destructures { userId, codeVerifier } from it; if either field is missing it throws BadRequestException('状态数据不完整') ('state data incomplete'). codeVerifier is required for the PKCE token exchange and userId to attribute the connection, so an entry lacking them is unusable.

Source

Thrown at project/aitoearn-electron/server/src/modules/plat/tiktok/tiktok.auth.service.ts:194

    //   parsedState = JSON.parse(decodeURIComponent(state));
    // } catch (error) {
    //   this.logger.error('无法解析状态参数:', error);
    //   throw new BadRequestException('无效的状态参数格式');
    // }

    // 从Redis获取保存的状态信息
    // const originalState = parsedState.state;

    const stateDataJson = await this.redisService.get(`tiktok:state:${state}`);
    if (!stateDataJson) {
      throw new BadRequestException('无效的状态参数或状态已过期');
    }
    // 解析状态数据
    const stateData = JSON.parse(stateDataJson);
    console.log('stateData:------', stateData);
    const { userId, codeVerifier } = stateData;
    if (!userId || !codeVerifier) {
      throw new BadRequestException('状态数据不完整');
    }

    // 删除Redis中的状态信息
    await this.redisService.del(`tiktok:state:${state}`);

    try {
      // 使用授权码交换令牌,并传入codeVerifier
      const tokenResponse = await this.exchangeCodeForTokens(code, codeVerifier);
      console.log("获取授权码成功!", tokenResponse);
      // 获取用户信息
      const userProfile = await this.getTikTokUserProfile(tokenResponse.access_token, tokenResponse.open_id);

      // 更新或创建TikTok账户信息
      await this.updateTikTokAccountInfo(
        userId,
        userProfile.open_id,
        tokenResponse.access_token,
        tokenResponse.refresh_token,

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Check what getAuthorizationUrl actually stores and confirm field names (userId, codeVerifier) match exactly
  2. Flush stale tiktok:state:* keys after changing the state payload schema, or version the keys (tiktok:state:v2:<state>)
  3. Have the user restart authorization to generate fresh, complete state data
  4. Add a validation/DTO check when writing state so incomplete entries are rejected at write time

Example fix

// before
const { userId, codeVerifier } = stateData;
if (!userId || !codeVerifier) {
  throw new BadRequestException('状态数据不完整');
}
// after
const { userId, codeVerifier } = stateData ?? {};
if (typeof userId !== 'string' || typeof codeVerifier !== 'string') {
  throw new BadRequestException('Stored TikTok state data is incomplete; restart authorization');
}
Defensive patterns

Strategy: type-guard

Validate before calling

const raw = await redis.get(`tiktok:state:${state}`);
const parsed = raw ? JSON.parse(raw) : null;
if (!parsed?.userId || !parsed?.codeVerifier) {
  return res.redirect('/connect/tiktok?reason=state_incomplete');
}

Type guard

function isCompleteState(d: unknown): d is { userId: string; codeVerifier: string } {
  return !!d && typeof d === 'object'
    && typeof (d as any).userId === 'string'
    && typeof (d as any).codeVerifier === 'string';
}

Try / catch

try {
  return await tiktokAuthService.handleAuthorizationCallback(state, code);
} catch (err) {
  if (err instanceof BadRequestException && err.message.includes('不完整')) {
    return res.redirect('/connect/tiktok?reason=state_corrupted');
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling handleAuthorizationCallback when the Redis value for the state parses as JSON but lacks userId or codeVerifier — i.e. the state was written with incomplete fields (older version of the writer code, manual Redis edit, corrupted or truncated value, or a JSON shape change between versions).

Common situations: Deploy where getAuthorizationUrl was changed (field renamed, e.g. codeVerifier -> code_verifier) but old-format state entries persist in Redis; someone manually injected test state into Redis; JSON.parse of a non-conforming cached value.

Related errors


AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31). Data as JSON: /api/errors/d10931755f348b6e. Report an issue: GitHub.