{"record":{"id":"bf25b2ad05dfaa55","repo":"yikart/AiToEarn","slug":"dashscope-happyhorse-does-not-support-image-tail","errorCode":null,"errorMessage":"DashScope HappyHorse does not support image_tail","messagePattern":"DashScope HappyHorse does not support image_tail","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-ai/src/core/ai/video/dashscope/dashscope.service.ts","lineNumber":153,"sourceCode":"\n    const metadata = await this.videoMetadataService.probeVideoMetadata(FileUtil.buildUrl(videoUrl))\n    const metadataDuration = Number(metadata.duration)\n    if (!Number.isFinite(metadataDuration) || metadataDuration <= 0) {\n      throw new BadRequestException('video duration is required')\n    }\n\n    return Math.min(Math.ceil(metadataDuration), this.getMaxDuration(modelConfig))\n  }\n\n  private async buildPayload(request: UserVideoGenerationRequestDto, modelConfig: DashscopeModelConfig): Promise<{\n    providerModel: string\n    mode: string\n    payload: DashscopeCreateVideoTaskRequest\n    duration?: number\n    resolution?: string\n  }> {\n    if (request.image_tail) {\n      throw new BadRequestException('DashScope HappyHorse does not support image_tail')\n    }\n\n    const imageUrls = this.collectImageUrls(request)\n    const videoUrl = request.video_url ?? request.videos?.[0]\n    const mode = this.resolveMode(request, modelConfig, imageUrls)\n    const resolution = request.resolution\n    const providerModel = this.getProviderModel(modelConfig, mode, resolution)\n    const ratio = request.ratio\n    const duration = await this.resolveVideoDuration(request, modelConfig, mode === 'video2video' ? videoUrl : undefined)\n    const prompt = request.prompt\n    const parameters: NonNullable<DashscopeCreateVideoTaskRequest['parameters']> = {}\n    if (resolution) {\n      parameters.resolution = resolution\n    }\n    parameters.watermark = request.watermark ?? false\n    if (request.seed != null) {\n      parameters.seed = request.seed\n    }","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-ai/src/core/ai/video/dashscope/dashscope.service.ts#L135-L171","documentation":"buildPayload for DashScope HappyHorse models rejects requests containing image_tail, since the DashScope HappyHorse API has no tail-image capability. It throws BadRequestException immediately before building the payload.","triggerScenarios":"Any video generation request to a HappyHorse (DashScope) model with request.image_tail set (e.g. clients that support start/end frames for other providers reusing the same DTO).","commonSituations":"Frontend sends image_tail unconditionally when a user supplies a second frame image; code shared across providers (e.g. one that supports image_tail like Kling) targeting DashScope.","solutions":["Omit image_tail for DashScope HappyHorse requests; use only image_head.","Route requests needing image_tail to a provider/model that supports it.","Strip image_tail in an adapter layer before calling DashScope generation.","If image_tail was intended as a second reference image, move it into the images array (respecting image count limits)."],"exampleFix":"// before\n{ model: 'wan-happyhorse', image_head: urlA, image_tail: urlB }\n// after\n{ model: 'wan-happyhorse', image_head: urlA } // image_tail unsupported on DashScope","handlingStrategy":"validation","validationCode":"if (model.startsWith('wan-happyhorse') && request.image_tail) {\n  throw new Error('Strip image_tail before calling DashScope HappyHorse; it is unsupported')\n}","typeGuard":"function happyhorseSafe<T extends { image_tail?: string }>(req: T, model: string): Omit<T, 'image_tail'> {\n  return model.includes('happyhorse') ? omit(req, 'image_tail') : req\n}","tryCatchPattern":"try {\n  await generate(request)\n} catch (err) {\n  if (err.message.includes('does not support image_tail')) {\n    const { image_tail, ...rest } = request\n    return generate(rest as typeof request) // retry without the unsupported field\n  }\n  throw err\n}","preventionTips":["Gate image_tail UI on provider capability, not on generic 'video generation'.","Maintain a per-model capability matrix in the client.","Sanitize request DTOs per provider in an adapter layer."],"tags":["capability-limitation","dashscope","bad-request"],"backgroundTag":"unsupported-parameter","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}