{"record":{"id":"8aed9e090d1e023c","repo":"yikart/AiToEarn","slug":"last-frame-requires-first-frame","errorCode":null,"errorMessage":"last_frame requires first_frame","messagePattern":"last_frame requires first_frame","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-ai/src/core/ai/video/volcengine/volcengine.service.ts","lineNumber":171,"sourceCode":"    const firstFrameImages = imageContents.filter(item => !item.role || item.role === ImageRole.FirstFrame)\n    const lastFrameImages = imageContents.filter(item => item.role === ImageRole.LastFrame)\n    const referenceImages = imageContents.filter(item => item.role === ImageRole.ReferenceImage)\n    const referenceVideos = videoContents.filter(item => item.role === VideoRole.ReferenceVideo)\n    const referenceAudios = audioContents.filter(item => item.role === AudioRole.ReferenceAudio)\n\n    const hasFrameScene = firstFrameImages.length > 0 || lastFrameImages.length > 0\n    const hasReferenceScene = referenceImages.length > 0 || referenceVideos.length > 0 || referenceAudios.length > 0\n\n    if (firstFrameImages.length > 1) {\n      throw new BadRequestException('Only one first frame image is allowed')\n    }\n\n    if (lastFrameImages.length > 1) {\n      throw new BadRequestException('Only one last frame image is allowed')\n    }\n\n    if (lastFrameImages.length > 0 && firstFrameImages.length === 0) {\n      throw new BadRequestException('last_frame requires first_frame')\n    }\n\n    if (hasFrameScene && hasReferenceScene) {\n      throw new BadRequestException('first_frame/last_frame and reference media cannot be mixed')\n    }\n\n    if (referenceAudios.length > 0 && referenceImages.length === 0 && referenceVideos.length === 0) {\n      throw new BadRequestException('reference_audio requires at least one reference image or reference video')\n    }\n  }\n\n  private normalizeRequest(request: UserVolcengineGenerationRequestDto) {\n    let prompt = ''\n    let inlineResolution: string | undefined\n    let inlineRatio: string | undefined\n    let inlineDuration: number | undefined\n    let inlineSeed: number | undefined\n    let inlineWatermark: boolean | undefined","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-ai/src/core/ai/video/volcengine/volcengine.service.ts#L153-L189","documentation":"Volcengine frame-interpolation generation requires a first frame when a last frame is provided. validateContent throws this BadRequestException when last_frame images exist but no first_frame image was supplied, because a last frame alone is not a valid generation mode.","triggerScenarios":"Sending content with exactly one last_frame image and zero first_frame images.","commonSituations":"Client mixes up role assignment (marking the start image as last_frame); UI only collects an end frame; refactor swapped role values.","solutions":["Add a first_frame image content item alongside the last_frame","If only one image is intended, assign it role first_frame instead","Validate the pair client-side: last_frame implies first_frame"],"exampleFix":"// before\ncontent: [{ type:'image_url', role:'last_frame', url: img }]\n// after\ncontent: [{ type:'image_url', role:'first_frame', url: start }, { type:'image_url', role:'last_frame', url: img }]","handlingStrategy":"validation","validationCode":"const hasLast = content.some(c => c.role === 'last_frame'); const hasFirst = content.some(c => c.role === 'first_frame'); if (hasLast && !hasFirst) throw new Error('last_frame requires first_frame')","typeGuard":"const isValidFramePair = (c: Content[]) => !c.some(i => i.role === 'last_frame') || c.some(i => i.role === 'first_frame')","tryCatchPattern":"try { await generate(req) } catch (e) { if (e instanceof BadRequestException && e.message === 'last_frame requires first_frame') { /* add a first_frame or change role */ } else throw e }","preventionTips":["Pair first/last frames together in UI selection","Never assign last_frame role to a lone image","Pre-validate frame role dependencies client-side"],"tags":["validation","volcengine","content-constraints"],"backgroundTag":"missing-required-companion-field","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}