yikart/AiToEarn · error · BadRequestException

userId is required

Error message

userId is required

What it means

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.

Source

Thrown at project/aitoearn-backend/apps/aitoearn-ai/src/core/ai/image/image.service.ts:124

      const contentType = imageUrlOrResponse.headers.get('content-type') || 'image/png'
      const buffer = Buffer.from(await imageUrlOrResponse.arrayBuffer())
      const result = await this.assetsService.uploadFromBuffer(userId, buffer, {
        type: AssetType.AiImage,
        mimeType: contentType,
      }, subPath)
      return result.asset.path
    }
  }

  /**
   * 图片生成
   */
  async generation(request: ImageGenerationDto) {
    const { user, ...params } = request
    const runtimeModel = this.resolveRuntimeImageModel(params.model, 'generation')

    if (!user) {
      throw new BadRequestException('userId is required')
    }

    if (runtimeModel === 'gpt-image-1') {
      delete params.response_format
      delete params.style
    }

    const result = await this.openaiService.createImageGeneration({
      ...params,
      model: runtimeModel,
    } as Omit<OpenAI.Images.ImageGenerateParams, 'user'> & { apiKey?: string })

    for (const image of result.data || []) {
      if (image.url) {
        image.url = await this.uploadImageToS3(image.url, user, `${request.model}`)
      }
      if (image.b64_json) {
        const mimeType = `image/${result.output_format || 'png'}`

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Ensure the caller is authenticated so the user object is attached to ImageGenerationDto before calling generation()
  2. If calling the service directly, populate request.user from your auth context (userId, userType)
  3. Check middleware/guards that extract the user; a silent failure there yields user === undefined
  4. Wrap callers like userGeneration so a missing user short-circuits with a clear 401/400 rather than reaching this point

Example fix

// before
await imageService.generation({ model: 'gpt-image-1', prompt })
// after
await imageService.generation({ model: 'gpt-image-1', prompt, user: { userId: ctx.userId, userType: ctx.userType } })
Defensive patterns

Strategy: validation

Validate before calling

function requireUser(dto: ImageGenerationDto) {
  if (!dto.user?.userId) throw new Error('user (with userId) must be provided for image generation')
  return dto
}

Type guard

function hasUser(dto: ImageGenerationDto): dto is ImageGenerationDto & { user: NonNullable<ImageGenerationDto['user']> } {
  return !!dto.user && typeof dto.user.userId === 'string' && dto.user.userId.length > 0
}

Try / catch

try {
  await imageService.generation(dto)
} catch (e) {
  if (e instanceof BadRequestException && e.message === 'userId is required') {
    throw new UnauthorizedException('Authentication required for image generation')
  }
  throw e
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


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