{"record":{"id":"097fa77716320d0a","repo":"yikart/AiToEarn","slug":"tweetid-userid-accountid","errorCode":null,"errorMessage":"tweetId, userId和accountId是必须的","messagePattern":"tweetId, userId和accountId是必须的","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"project/aitoearn-electron/server/src/modules/plat/twitter/twitter.controller.ts","lineNumber":261,"sourceCode":"  }\n\n  /**\n   * 获取推文详情\n   */\n  @Get('tweets/detail')\n  @ApiOperation({ summary: '获取推文详情' })\n  @ApiQuery({ name: 'tweetId', type: 'string', description: '推文ID' })\n  // @ApiQuery({ name: 'userId', required: true, description: '用户ID' })\n  @ApiQuery({ name: 'accountId', required: true, description: 'Twitter账号ID' })\n  async getTweetDetail(\n    @GetToken() systemToken: TokenInfo,\n    @Query('tweetId') tweetId: string,\n    // @Query('userId') userId: string,\n    @Query('accountId') accountId: string,\n  ) {\n    const userId = systemToken.id;\n    if (!tweetId || !userId || !accountId) {\n      throw new BadRequestException('tweetId, userId和accountId是必须的');\n    }\n\n    const accessToken = await this.twitterAuthService.getUserAccessToken(accountId);\n    return this.twitterService.getTweetDetail(accessToken, userId, accountId, tweetId);\n  }\n\n  /**\n   * 获取推文统计数据\n   */\n  @Get('tweets/metrics')\n  @ApiOperation({ summary: '获取推文统计数据' })\n  @ApiQuery({ name: 'tweetId', type: 'string', description: '推文ID' })\n  // @ApiQuery({ name: 'userId', required: true, description: '用户ID' })\n  @ApiQuery({ name: 'accountId', required: true, description: 'Twitter账号ID' })\n  async getTweetMetrics(\n    @GetToken() systemToken: TokenInfo,\n    @Query('tweetId') tweetId: string,\n    // @Query('userId') userId: string,","sourceCodeStart":243,"sourceCodeEnd":279,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-electron/server/src/modules/plat/twitter/twitter.controller.ts#L243-L279","documentation":"Thrown by the getTweetDetail endpoint when the query string is missing 'tweetId' or 'accountId' (or the token id is empty). The controller validates all three inputs before fetching the account's access token and calling the Twitter API for tweet details. It is a 400-level input guard, not a Twitter API failure.","triggerScenarios":"GET request to getTweetDetail without ?tweetId=... or ?accountId=... query parameters, or an empty-string tweetId/accountId, or a system token resolving to a falsy userId.","commonSituations":"Client builds the URL but forgets to URL-encode/append one parameter; accountId is empty because the account was not selected in the UI; calling the endpoint without authenticating so systemToken.id is missing.","solutions":["Add both tweetId and accountId as query parameters to the GET request.","Ensure tweetId is the full numeric Twitter status id string (not truncated or empty).","Verify the request includes a valid system token so userId = systemToken.id is non-empty.","Check the client isn't sending these in the body — this endpoint reads them from @Query()."],"exampleFix":"// before\nGET /twitter/tweet/detail\n// after\nGET /twitter/tweet/detail?tweetId=1234567890&accountId=acct_123","handlingStrategy":"validation","validationCode":"if (!tweetId || !accountId) throw new Error('tweetId和accountId是必须的');\nconst url = `/twitter/tweet/detail?tweetId=${encodeURIComponent(tweetId)}&accountId=${encodeURIComponent(accountId)}`;","typeGuard":"function canFetchDetail(p: unknown): p is { tweetId: string; accountId: string } {\n  const o = p as any;\n  return typeof o?.tweetId === 'string' && o.tweetId.length > 0 && typeof o?.accountId === 'string' && o.accountId.length > 0;\n}","tryCatchPattern":"try {\n  const detail = await api.get(url);\n} catch (e) {\n  if (e.response?.status === 400) console.error('缺少必要参数:', e.response.data?.message);\n}","preventionTips":["Validate query params exist before navigating/fetching.","Keep the selected accountId in app state and pass it on every tweet call.","URL-encode all query parameter values.","Handle 401 separately to refresh tokens rather than confusing it with param errors."],"tags":["nestjs","validation","bad-request","missing-parameter","query-params"],"backgroundTag":"missing-required-parameter","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}