yikart/AiToEarn · error · BadRequestException

userId和accountId是必须的

Error message

userId和accountId是必须的

What it means

GET /plat/twitter/timeline derives userId from the authenticated system JWT (@GetToken()) and takes accountId from the query. It throws BadRequestException('userId和accountId是必须的') when either is falsy — i.e. the request was unauthenticated/expired (no systemToken.id) or the accountId query param was omitted. After validation it fetches an access token via getUserAccessToken and calls the timeline service.

Source

Thrown at project/aitoearn-electron/server/src/modules/plat/twitter/twitter.controller.ts:168

  /**
   * 获取用户的Twitter时间线
   */
  @Get('timeline')
  @ApiOperation({ summary: '获取用户的Twitter时间线' })
  // @ApiQuery({ name: 'userId', required: true, description: '用户ID' })
  @ApiQuery({ name: 'accountId', required: true, description: '账号ID' })
  @ApiQuery({ name: 'maxResults', required: false, description: '最大结果数', type: 'number' })
  async getUserTimeline(
    @GetToken() systemToken: TokenInfo,
    // @Query('userId') userId: string,
    @Query('accountId') accountId: string,
    @Query('maxResults') maxResults?: number,
  ) {

    const userId = systemToken.id;
    if (!userId || !accountId) {
      throw new BadRequestException('userId和accountId是必须的');
    }

    const accessToken = await this.twitterAuthService.getUserAccessToken(accountId);

    return this.twitterService.getUserTimeline(accessToken, userId, accountId, maxResults);
  }

  /**
   * 发布新推文
   */
  @Post('tweets/create')
  @ApiOperation({ summary: '发布新推文' })
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        // userId: { type: 'string', description: '用户ID' },
        accountId: { type: 'string', description: 'Twitter账号ID' },

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Re-authenticate to get a fresh system JWT and send it in the Authorization header
  2. Add ?accountId=<id> to the request URL
  3. Client-side guard: if (!authToken || !accountId) skip/redirect to login
  4. If 401/empty-token errors follow (errors 450-452), re-authorize the Twitter account itself

Example fix

// before
await api.get('/plat/twitter/timeline');
// after
await api.get('/plat/twitter/timeline', {
  params: { accountId },
  headers: { Authorization: `Bearer ${systemToken}` },
});
Defensive patterns

Strategy: validation

Validate before calling

if (!systemToken || !accountId) {
  redirectToLogin(); // userId comes from the JWT; no token means the 400
}
await api.get('/plat/twitter/timeline', { params: { accountId }, headers: { Authorization: `Bearer ${systemToken}` } });

Type guard

function isTimelineRequest(t: unknown, accountId: unknown): accountId is string {
  return !!t && typeof (t as any).id === 'string' && (t as any).id.length > 0
    && typeof accountId === 'string' && accountId.length > 0;
}

Try / catch

try {
  return await api.get('/plat/twitter/timeline', { params: { accountId } });
} catch (e) {
  if (e.response?.status === 400) {
    // missing JWT-derived userId or accountId — re-login then retry
    await relogin();
    return await api.get('/plat/twitter/timeline', { params: { accountId } });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling /plat/twitter/timeline without an Authorization header or with an expired JWT (userId undefined); omitting ?accountId=...; whitespace-only accountId.

Common situations: Cron jobs/scripts hitting the endpoint without a login token; token expiry mid-session; frontend calling before the selected account id resolves; test tools like curl missing the auth header.

Understand the failure class

Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.

Related errors


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