yikart/AiToEarn · warning · BadRequestException

imageSize must be one of 1K, 2K, or 4K

Error message

imageSize must be one of 1K, 2K, or 4K

What it means

getOpenAIImageSizeProfile maps an imageSize tier ('1K'|'2K'|'4K') to pixel budgets used to compute OpenAI image dimensions. Any other value hits the default branch and throws a Nest BadRequestException with message 'imageSize must be one of 1K, 2K, or 4K' — a 400-class client input error, not an AppException.

Source

Thrown at project/aitoearn-backend/apps/aitoearn-ai/src/core/draft-generation/draft-generation.service.ts:94

  None = 'none',
  Reference = 'reference',
  Edit = 'edit',
  Ignored = 'ignored',
}

const OPENAI_IMAGE_DEFAULT_ASPECT_RATIO = '2:3'
const OPENAI_IMAGE_DEFAULT_RESOLUTION = '1K'

function getOpenAIImageSizeProfile(imageSize: string): { maxEdge: number, maxPixels: number, squareSize?: string } {
  switch (imageSize) {
    case '1K':
      return { maxEdge: 1536, maxPixels: 1536 * 1024, squareSize: '1024x1024' }
    case '2K':
      return { maxEdge: 2560, maxPixels: 2560 * 1440 }
    case '4K':
      return { maxEdge: 3840, maxPixels: 3840 * 2160 }
    default:
      throw new BadRequestException('imageSize must be one of 1K, 2K, or 4K')
  }
}
const OPENAI_IMAGE_SIZE_MULTIPLE = 16
const OPENAI_IMAGE_MIN_ASPECT_RATIO = 1 / 3
const OPENAI_IMAGE_MAX_ASPECT_RATIO = 3

function getGreatestCommonDivisor(left: number, right: number): number {
  let a = Math.abs(left)
  let b = Math.abs(right)

  while (b !== 0) {
    const next = a % b
    a = b
    b = next
  }

  return a
}

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Validate imageSize in the DTO with a Zod enum ['1K','2K','4K'] so invalid values are rejected with a field-level 400 before the service
  2. Normalize case (toUpperCase) at the boundary to tolerate '1k'
  3. Update callers to send only the canonical tier strings
  4. Map legacy size vocabulary to tiers in the controller/DTO transform

Example fix

// before
imageSize: '1k'
// after
imageSize: z.enum(['1K', '2K', '4K']).default('2K') // DTO level
// caller sends: imageSize: '1K'
Defensive patterns

Strategy: validation

Validate before calling

const IMAGE_SIZES = ['1K', '2K', '4K'] as const
const normalized = typeof input.imageSize === 'string' ? input.imageSize.toUpperCase() : input.imageSize
if (!IMAGE_SIZES.includes(normalized)) {
  throw new Error(`imageSize must be one of 1K, 2K, or 4K, got: ${input.imageSize}`)
}

Type guard

type ImageSize = '1K' | '2K' | '4K'
function isImageSize(v: unknown): v is ImageSize {
  return v === '1K' || v === '2K' || v === '4K'
}

Try / catch

try {
  await draftGenerationService.generateImageText({ ...dto, imageSize })
} catch (e) {
  if (e instanceof BadRequestException && e.message.includes('imageSize must be one of')) {
    return badRequest('imageSize must be 1K, 2K, or 4K')
  }
  throw e
}

Prevention

When it happens

Trigger: A draft-generation image request supplies imageSize (or a derived size profile) with a value like '1024', '1k' (lowercase), 'HD', or undefined-coerced garbage instead of exactly '1K', '2K', or '4K'.

Common situations: Client sends lowercase '1k' or a numeric pixel size; an older API consumer uses the legacy size vocabulary ('auto', '1024x1024'); DTO lacks an enum validation so bad values reach the service.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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