{"record":{"id":"3e56df0d4a72c43b","repo":"yikart/AiToEarn","slug":"userid-is-required","errorCode":null,"errorMessage":"userId is required","messagePattern":"userId is required","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-ai/src/core/ai/image/image.service.ts","lineNumber":124,"sourceCode":"      const contentType = imageUrlOrResponse.headers.get('content-type') || 'image/png'\n      const buffer = Buffer.from(await imageUrlOrResponse.arrayBuffer())\n      const result = await this.assetsService.uploadFromBuffer(userId, buffer, {\n        type: AssetType.AiImage,\n        mimeType: contentType,\n      }, subPath)\n      return result.asset.path\n    }\n  }\n\n  /**\n   * 图片生成\n   */\n  async generation(request: ImageGenerationDto) {\n    const { user, ...params } = request\n    const runtimeModel = this.resolveRuntimeImageModel(params.model, 'generation')\n\n    if (!user) {\n      throw new BadRequestException('userId is required')\n    }\n\n    if (runtimeModel === 'gpt-image-1') {\n      delete params.response_format\n      delete params.style\n    }\n\n    const result = await this.openaiService.createImageGeneration({\n      ...params,\n      model: runtimeModel,\n    } as Omit<OpenAI.Images.ImageGenerateParams, 'user'> & { apiKey?: string })\n\n    for (const image of result.data || []) {\n      if (image.url) {\n        image.url = await this.uploadImageToS3(image.url, user, `${request.model}`)\n      }\n      if (image.b64_json) {\n        const mimeType = `image/${result.output_format || 'png'}`","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-ai/src/core/ai/image/image.service.ts#L106-L142","documentation":"generation() destructures the per-user info from ImageGenerationDto and requires it to run the generation with billing/attribution. When request.user is absent it throws BadRequestException('userId is required') before calling any model. This is a guard against unauthenticated or mis-shaped requests reaching expensive image generation.","triggerScenarios":"An API call to the image generation endpoint omits the user object in the request body, an internal caller (e.g. userGeneration path via MCP/agent tools) forwards a DTO built without user info, or auth middleware failed to attach the user but the route was still invoked.","commonSituations":"Calling the service internally (not via the controller) and forgetting to populate user; token/auth issues causing the user field to be dropped; DTO constructed manually in tests or scripts without user.","solutions":["Ensure the caller is authenticated so the user object is attached to ImageGenerationDto before calling generation()","If calling the service directly, populate request.user from your auth context (userId, userType)","Check middleware/guards that extract the user; a silent failure there yields user === undefined","Wrap callers like userGeneration so a missing user short-circuits with a clear 401/400 rather than reaching this point"],"exampleFix":"// before\nawait imageService.generation({ model: 'gpt-image-1', prompt })\n// after\nawait imageService.generation({ model: 'gpt-image-1', prompt, user: { userId: ctx.userId, userType: ctx.userType } })","handlingStrategy":"validation","validationCode":"function requireUser(dto: ImageGenerationDto) {\n  if (!dto.user?.userId) throw new Error('user (with userId) must be provided for image generation')\n  return dto\n}","typeGuard":"function hasUser(dto: ImageGenerationDto): dto is ImageGenerationDto & { user: NonNullable<ImageGenerationDto['user']> } {\n  return !!dto.user && typeof dto.user.userId === 'string' && dto.user.userId.length > 0\n}","tryCatchPattern":"try {\n  await imageService.generation(dto)\n} catch (e) {\n  if (e instanceof BadRequestException && e.message === 'userId is required') {\n    throw new UnauthorizedException('Authentication required for image generation')\n  }\n  throw e\n}","preventionTips":["Build the DTO from an authenticated request context, never from raw client body alone","Ensure auth guards run before the controller populates user","In internal calls/tests, always populate user: { userId, userType }","Add a constructor-level validation (class-validator @IsDefined on user) to fail early"],"tags":["validation","auth","user-id"],"backgroundTag":"missing-required-field","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}