yikart/AiToEarn · error · Error

Video upload failed

Error message

Video upload failed

What it means

After a playlist insert (videos.insert/upload flow) the service checks response.data and throws a generic Error('Video upload failed') when the response body is falsy, i.e. Google returned 2xx without usable payload data. It is a weak success-check: the real cause is hidden and the console.error in the catch rethrows whatever preceded it.

Source

Thrown at project/aitoearn-electron/server/src/modules/plat/youtube/youtube.service.ts:1055

      // 调用 YouTube API 上传视频
      const response = await this.youtubeService.playlistItems.insert(
        {
          auth: oauth2Client,
          part: 'snippet,status, id, contentDetails',
          requestBody
        }
      );

    //   const response = {    "data": {
    //     "id": "7RckZHFBu7A"
    // },}
      // 返回上传的视频 ID
      if (response.data) {
        console.log('Playlist insert successfully:', response.data);
        return response.data;
      } else {
        throw new Error('Video upload failed');
      }
    } catch (error) {
      console.error('Error uploading video:', error);
      throw error;
    }

  }


  /**
 * 获取播放列表项。
 */
    async getPlayItemsList(accessToken, playlistId, itemsIds, maxResults, pageToken) {
      // 设置 OAuth2 客户端凭证
      this.oauth2Service.setCredentials(accessToken);
      const oauth2Client = this.oauth2Service.getClient();

    // 根据传入的参数来选择一个有效的请求参数

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Log the full response (status, headers, body) before this check to see why data is missing.
  2. Verify the upload request builds correct metadata (snippet, status) and required parts.
  3. Check token validity and quota (upload quota 403/412) — a failed call may surface as empty data.
  4. Add explicit response.status check (e.g. require 200/201) and include status in the thrown message.
  5. Retry the upload once after confirming network/proxy stability.

Example fix

// before
if (response.data) { return response.data; } else { throw new Error('Video upload failed'); }
// after
if (response.status === 200 && response.data?.id) { return response.data; }
throw new Error(`Video upload failed: status=${response.status} body=${JSON.stringify(response.data)}`);
Defensive patterns

Strategy: try-catch

Validate before calling

if (!response || typeof response.status !== 'number') throw new Error('No response received from YouTube API');

Type guard

function hasUploadPayload(res: { status?: number; data?: { id?: string } | null }): res is { status: number; data: { id: string } } {
  return typeof res.status === 'number' && !!res.data && typeof res.data.id === 'string';
}

Try / catch

try {
  const result = await client.uploadVideo(accountId, file);
  if (!result?.id) throw new Error(`Upload returned no id: ${JSON.stringify(result)}`);
} catch (error) {
  console.error('Upload failed:', { status: error?.response?.status, data: error?.response?.data, message: error?.message });
  // retry once with backoff for transient/network errors, then surface details
}

Prevention

When it happens

Trigger: The YouTube API call resolves but response.data is undefined/null/empty object; network proxies or retry layers returning empty 2xx bodies; upstream error thrown earlier and rethrown through this catch with this message logged context.

Common situations: Rate-limited or flaky networks producing empty responses; misconfigured request part/body so the API returns 204/no content; stale tokens causing an earlier failure that surfaces only through the generic catch.

Related errors


AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31). Data as JSON: /api/errors/05fa104b51b7c5ae. Report an issue: GitHub.