yikart/AiToEarn · error · BadRequestException
image aspectRatio must use positive integer WIDTH:HEIGHT
Error message
image aspectRatio must use positive integer WIDTH:HEIGHT
What it means
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.
Source
Thrown at project/aitoearn-backend/apps/aitoearn-ai/src/core/draft-generation/draft-generation.service.ts:280
const modelConfig = config.ai.draftGeneration.imageModels.find(m => m.model === model)
if (!modelConfig) {
throw new AppException(ResponseCode.InvalidModel)
}
return modelConfig
}
private resolveOpenAIImageSize(aspectRatio?: string, imageSize = OPENAI_IMAGE_DEFAULT_RESOLUTION): string {
const sizeProfile = getOpenAIImageSizeProfile(imageSize)
const parts = (aspectRatio ?? OPENAI_IMAGE_DEFAULT_ASPECT_RATIO).split(':')
if (parts.length !== 2) {
throw new BadRequestException('image aspectRatio must use WIDTH:HEIGHT')
}
const widthRatio = Number(parts[0])
const heightRatio = Number(parts[1])
if (!Number.isInteger(widthRatio) || !Number.isInteger(heightRatio) || widthRatio <= 0 || heightRatio <= 0) {
throw new BadRequestException('image aspectRatio must use positive integer WIDTH:HEIGHT')
}
const ratio = widthRatio / heightRatio
if (ratio < OPENAI_IMAGE_MIN_ASPECT_RATIO || ratio > OPENAI_IMAGE_MAX_ASPECT_RATIO) {
throw new BadRequestException('image aspectRatio must be between 1:3 and 3:1')
}
if (widthRatio === heightRatio) {
return sizeProfile.squareSize ?? this.resolveScaledOpenAIImageSize(widthRatio, heightRatio, sizeProfile)
}
return this.resolveScaledOpenAIImageSize(widthRatio, heightRatio, sizeProfile)
}
private resolveScaledOpenAIImageSize(
widthRatio: number,
heightRatio: number,
sizeProfile: { maxEdge: number, maxPixels: number },View on GitHub (pinned to d3aa8bea5b)
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).
Example fix
// before
aspectRatio: `${width/height}:1` // '1.5:1'
// after
const g = gcd(width, height)
aspectRatio: `${width/g}:${height/g}` // '3:2' Defensive patterns
Strategy: validation
Validate before calling
function isValidRatio(a, b) { return Number.isInteger(Number(a)) && Number.isInteger(Number(b)) && Number(a) > 0 && Number(b) > 0 }
const [w, h] = String(aspectRatio).split(':')
if (!isValidRatio(w, h)) throw new Error('aspectRatio must use positive integers, e.g. 3:2 not 1.5:1') Type guard
function isIntegerRatio(v: unknown): v is string {
if (typeof v !== 'string') return false
const [w, h] = v.split(':').map(Number)
return Number.isInteger(w) && Number.isInteger(h) && w > 0 && h > 0
} Try / catch
try {
await generateDraft({ aspectRatio })
} catch (e) {
if (e.status === 400 && e.message.includes('positive integer')) {
aspectRatio = toIntegerRatio(aspectRatio) // e.g. scale 1.5:1 -> 3:2 and retry
} else throw e
} Prevention
- 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.
When it happens
Trigger: aspectRatio like '16.5:9', 'a:b', '0:9', '-16:9', or 'NaN:1' passed to draft generation's OpenAI image size resolution.
Common situations: Passing fractional ratios like '1.5:1' instead of scaling to integers ('3:2'); empty string halves producing NaN; programmatic ratio computation producing floats.
Related errors
- imageSize must be one of 1K, 2K, or 4K
- image aspectRatio must use WIDTH:HEIGHT
- image aspectRatio must be between 1:3 and 3:1
- video duration is required
- OpenAI does not support multiple images
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/822fdfdc510b477d.
Report an issue: GitHub.