{"record":{"id":"822fdfdc510b477d","repo":"yikart/AiToEarn","slug":"image-aspectratio-must-use-positive-integer-width","errorCode":null,"errorMessage":"image aspectRatio must use positive integer WIDTH:HEIGHT","messagePattern":"image aspectRatio must use positive integer WIDTH:HEIGHT","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-ai/src/core/draft-generation/draft-generation.service.ts","lineNumber":280,"sourceCode":"    const modelConfig = config.ai.draftGeneration.imageModels.find(m => m.model === model)\n    if (!modelConfig) {\n      throw new AppException(ResponseCode.InvalidModel)\n    }\n\n    return modelConfig\n  }\n\n  private resolveOpenAIImageSize(aspectRatio?: string, imageSize = OPENAI_IMAGE_DEFAULT_RESOLUTION): string {\n    const sizeProfile = getOpenAIImageSizeProfile(imageSize)\n    const parts = (aspectRatio ?? OPENAI_IMAGE_DEFAULT_ASPECT_RATIO).split(':')\n    if (parts.length !== 2) {\n      throw new BadRequestException('image aspectRatio must use WIDTH:HEIGHT')\n    }\n\n    const widthRatio = Number(parts[0])\n    const heightRatio = Number(parts[1])\n    if (!Number.isInteger(widthRatio) || !Number.isInteger(heightRatio) || widthRatio <= 0 || heightRatio <= 0) {\n      throw new BadRequestException('image aspectRatio must use positive integer WIDTH:HEIGHT')\n    }\n\n    const ratio = widthRatio / heightRatio\n    if (ratio < OPENAI_IMAGE_MIN_ASPECT_RATIO || ratio > OPENAI_IMAGE_MAX_ASPECT_RATIO) {\n      throw new BadRequestException('image aspectRatio must be between 1:3 and 3:1')\n    }\n\n    if (widthRatio === heightRatio) {\n      return sizeProfile.squareSize ?? this.resolveScaledOpenAIImageSize(widthRatio, heightRatio, sizeProfile)\n    }\n\n    return this.resolveScaledOpenAIImageSize(widthRatio, heightRatio, sizeProfile)\n  }\n\n  private resolveScaledOpenAIImageSize(\n    widthRatio: number,\n    heightRatio: number,\n    sizeProfile: { maxEdge: number, maxPixels: number },","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-ai/src/core/draft-generation/draft-generation.service.ts#L262-L298","documentation":"After splitting aspectRatio into two parts, resolveOpenAIImageSize coerces both to Number and requires them to be positive integers. Non-numeric tokens, floats, zero, or negative values throw this BadRequestException. It refines the format error [90] with numeric constraints.","triggerScenarios":"aspectRatio like '16.5:9', 'a:b', '0:9', '-16:9', or 'NaN:1' passed to draft generation's OpenAI image size resolution.","commonSituations":"Passing fractional ratios like '1.5:1' instead of scaling to integers ('3:2'); empty string halves producing NaN; programmatic ratio computation producing floats.","solutions":["Use positive integer ratio components, e.g. '3:2' instead of '1.5:1'.","Round/multiply fractional ratios to integers client-side before sending.","Trim inputs and validate with a regex like /^\\d+:\\d+$/ before the API call.","Keep ratios within 1:3..3:1 to also pass the range check (error 92)."],"exampleFix":"// before\naspectRatio: `${width/height}:1` // '1.5:1'\n// after\nconst g = gcd(width, height)\naspectRatio: `${width/g}:${height/g}` // '3:2'","handlingStrategy":"validation","validationCode":"function isValidRatio(a, b) { return Number.isInteger(Number(a)) && Number.isInteger(Number(b)) && Number(a) > 0 && Number(b) > 0 }\nconst [w, h] = String(aspectRatio).split(':')\nif (!isValidRatio(w, h)) throw new Error('aspectRatio must use positive integers, e.g. 3:2 not 1.5:1')","typeGuard":"function isIntegerRatio(v: unknown): v is string {\n  if (typeof v !== 'string') return false\n  const [w, h] = v.split(':').map(Number)\n  return Number.isInteger(w) && Number.isInteger(h) && w > 0 && h > 0\n}","tryCatchPattern":"try {\n  await generateDraft({ aspectRatio })\n} catch (e) {\n  if (e.status === 400 && e.message.includes('positive integer')) {\n    aspectRatio = toIntegerRatio(aspectRatio) // e.g. scale 1.5:1 -> 3:2 and retry\n  } else throw e\n}","preventionTips":["Convert fractional ratios to integers by multiplying both sides (1.5:1 -> 3:2).","Never send empty, NaN, zero, or negative ratio components.","Validate with Number.isInteger on both halves before calling.","Reduce ratios with GCD to keep components small integers."],"tags":["validation","bad-request","image-generation"],"backgroundTag":"aspect-ratio-format-invalid","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}