{"record":{"id":"5c71544cea3dd82e","repo":"yikart/AiToEarn","slug":"s3downloadfilefailed","errorCode":"S3DownloadFileFailed","errorMessage":"S3DownloadFileFailed","messagePattern":"S3DownloadFileFailed","errorType":"error_code","errorClass":"AppException","httpStatus":400,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-ai/src/core/ai/video/openai/openai.service.ts","lineNumber":82,"sourceCode":"\n    return { id: result.id }\n  }\n\n  /**\n   * OpenAI 视频创建\n   */\n  async createVideo(request: UserOpenAIVideoCreateRequestDto) {\n    const { userId, userType, model, prompt, input_reference, seconds, size } = request\n\n    const startedAt = new Date()\n\n    // 如果 input_reference 是 URL，需要先 fetch 后传入 Response\n    let inputReferenceUploadable: Response | undefined\n    if (input_reference) {\n      const resolvedInputReference = await this.resolveRelayText(input_reference)\n      const response = await fetch(resolvedInputReference)\n      if (!response.ok) {\n        throw new AppException(ResponseCode.S3DownloadFileFailed)\n      }\n      inputReferenceUploadable = response\n    }\n\n    const result = await this.aiAvailability.executeAsync(\n      { provider: 'openai', operation: 'videoGeneration', model: model || 'sora-2' },\n      () => this.openaiLibService.createVideo({\n        prompt,\n        input_reference: inputReferenceUploadable,\n        model: model as 'sora-2' | 'sora-2-pro',\n        // SDK 类型定义有误，实际支持 '10' | '15' | '25'\n        seconds: seconds as '4' | '8' | '12' | undefined,\n        size,\n      }),\n      r => r.id,\n    )\n\n    const aiLog = await this.aiLogRepo.create({","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-ai/src/core/ai/video/openai/openai.service.ts#L64-L100","documentation":"createVideo fetches the input_reference image URL before uploading it to OpenAI. If the fetch returns a non-OK HTTP status (404, 403, timeout page, etc.), the service throws AppException(ResponseCode.S3DownloadFileFailed) because the reference image could not be downloaded for the video generation request.","triggerScenarios":"Calling createVideo with input_reference set to a URL whose fetch fails: presigned URL expired, private S3/OSS object not accessible, DNS failure, or relay media resolution returned an unreachable URL. Any non-2xx response.ok triggers the throw.","commonSituations":"Presigned URLs generated minutes earlier have expired by generation time; storage bucket permissions changed; relay media resolver disabled (@Optional dependency missing) so an internal/private URL is fetched directly; typo in stored asset path.","solutions":["Regenerate a fresh presigned/accessible URL for the reference image before calling createVideo (see toAccessibleUrl)","Verify the image URL is publicly fetchable from the AI service (curl it from the host)","Ensure RelayMediaResolverService is provided so relay/internal URLs are resolved before fetching","Check bucket ACL/policy so the object is readable by the service"],"exampleFix":"// before\ninput_reference: 'https://s3.aitoearn.cn/private/ref.png' // expired presigned URL\n// after\ninput_reference: await this.toAccessibleUrl(assetPath) // fresh presigned URL","handlingStrategy":"validation","validationCode":"const res = await fetch(inputReferenceUrl, { method: 'HEAD' })\nif (!res.ok) throw new Error(`Reference image unreachable: HTTP ${res.status}`)","typeGuard":null,"tryCatchPattern":"try {\n  await openaiVideoService.createVideo({ input_reference: url, ... })\n} catch (e) {\n  if (e instanceof AppException && e.code === ResponseCode.S3DownloadFileFailed) {\n    // refresh presigned URL and retry once\n  }\n}","preventionTips":["Generate presigned URLs with sufficient expiry shortly before the call","HEAD-check reference URLs before submitting the generation task","Ensure the relay media resolver is wired so internal URLs are converted to fetchable ones","Verify storage bucket read permissions from the AI service host"],"tags":["s3","download","network","fetch","openai-video"],"backgroundTag":"s3-download-failed","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}