yikart/AiToEarn · error · BadRequestException

获取Twitter时间线失败: ${error.response?.data?.error || error.messa

Error message

获取Twitter时间线失败: ${error.response?.data?.error || error.message}

What it means

getUserTimeline catches any failure from the upstream Twitter API HTTP call and rethrows it as a Nest BadRequestException prefixed with '获取Twitter时间线失败:'. The message embeds error.response?.data?.error (Twitter's error payload) or the axios error message. Common upstream causes are an expired/revoked access token, rate-limit (429), or bad query params.

Source

Thrown at project/aitoearn-electron/server/src/modules/plat/twitter/twitter.service.ts:66

      };
      console.log("请求参数:", params);
      // console.log("accessToken:", accessToken);
      const response = await lastValueFrom(
        this.httpService.get(url, {
          params,
          headers: {
            Authorization: `Bearer ${accessToken}`,
          },
        })
      );
      console.log("==============response============");
      console.log(response);
      return response.data
    } catch (error) {
      console.error('完整错误对象:', JSON.stringify(error.response?.data || error.message));

      this.logger.error(`获取Twitter时间线失败: ${error.message}`, error.stack);
      throw new BadRequestException(`获取Twitter时间线失败: ${error.response?.data?.error || error.message}`);
    }
  }

  /**
   * 发布新推文
   * @param userId 用户ID
   * @param accountId Twitter账号ID
   * @param text 推文内容
   * @param mediaIds 媒体ID数组
   * @returns 发布结果
   */
  async createTweet(accessToken: string, userId: string, accountId: string, text: string, mediaIds?: string[]) {
    // 获取当前最大的 id
    const maxRecord = await this.PubRecordModel.findOne().sort({ id: -1 });
    const newId = maxRecord ? maxRecord.id + 1 : 1;

    try {

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Inspect error.response.data.error in the message to get Twitter's specific error code; fix the root cause (usually re-auth the account to refresh the access token).
  2. If 429, back off until the rate-limit window resets (respect x-rate-limit-reset headers).
  3. If 401/403, re-run the Twitter OAuth flow for that accountId and store the new token.
  4. Add retry with exponential backoff for transient network/5xx errors instead of surfacing immediately.
  5. Note this endpoint wraps all upstream errors as 400 — check server logs for the real status.
Defensive patterns

Strategy: try-catch

Validate before calling

const token = await getStoredAccessToken(accountId);
if (!token) await reauthenticate(accountId); // avoid calling with a dead token

Type guard

function isTwitterApiError(msg: string): boolean {
  return typeof msg === 'string' && msg.startsWith('获取Twitter时间线失败:');
}

Try / catch

try {
  const timeline = await api.get('/twitter/timeline', { params: { accountId } });
} catch (e) {
  const msg = e.response?.data?.message || '';
  if (msg.includes('获取Twitter时间线失败')) {
    const detail = msg.split(': ').slice(1).join(': ');
    if (/429|rate limit/i.test(detail)) await backoffThenRetry();
    else if (/401|Unauthorized/i.test(detail)) await reauthenticate(accountId);
  }
}

Prevention

When it happens

Trigger: Twitter API returns non-2xx when fetching the user timeline: OAuth1 access token invalid/expired, 401/403 permissions, 429 rate limit, or network failure — any axios rejection inside getUserTimeline.

Common situations: User reconnected the account so the stored token was revoked; app hit the 15-min window rate limit; Twitter API v2 tier lacks required access; transient network/DNS outage on the server.

Related errors


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