{"record":{"id":"e29a73fcf262f5b0","repo":"yikart/AiToEarn","slug":"youtube","errorCode":null,"errorMessage":"未检测到可用的 YouTube 频道，请先创建频道","messagePattern":"未检测到可用的 YouTube 频道，请先创建频道","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"project/aitoearn-electron/server/src/modules/plat/youtube/youtube.service.ts","lineNumber":685,"sourceCode":" */\n  async uploadVideo(userId, accountId, accessToken, file, title, description, keywords, categoryId, privacyStatus, publishAt) {\n    // 获取当前最大的 id\n    const maxRecord = await this.PubRecordModel.findOne().sort({ id: -1 });\n    const newId = maxRecord ? maxRecord.id + 1 : 1;\n    try {\n      // 设置 OAuth2 客户端凭证\n      this.oauth2Service.setCredentials(accessToken);\n      const oauth2Client = this.oauth2Service.getClient();\n\n      try {\n        const channelInfo = await this.youtubeService.channels.list({\n          part: ['snippet'],\n          mine: true,\n          auth: oauth2Client,\n        });\n\n        if (!channelInfo.data.items || channelInfo.data.items.length === 0) {\n          throw new Error('未检测到可用的 YouTube 频道，请先创建频道');\n        }\n\n        // 可以上传\n      } catch (err) {\n        if (err.errors?.[0]?.reason === 'youtubeSignupRequired') {\n          throw new Error('当前账号未启用 YouTube，请先创建频道');\n        }\n      }\n\n\n      // 准备视频的元数据\n      const fileStream = Readable.from(file.buffer); // 使用文件的 Buffer 转为可读取流\n      const fileSize = file.size;  // 获取文件大小\n\n      // 构造请求体\n      let requestBody: any = {\n        snippet: {\n          title: title,","sourceCodeStart":667,"sourceCodeEnd":703,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-electron/server/src/modules/plat/youtube/youtube.service.ts#L667-L703","documentation":"During uploadVideo, the service calls youtube.channels.list({ mine: true }) to verify the authenticated account owns a YouTube channel. If Google returns no items (empty data.items) the service throws this Error: the OAuth account exists but has no YouTube channel. A related path converts a youtubeSignupRequired API error into the sibling message 494.","triggerScenarios":"Uploading a video with an OAuth token whose Google account has never created a YouTube channel; the channels.list(mine=true) response returns items: [] or undefined; err.errors[0].reason === 'youtubeSignupRequired' from the channels call.","commonSituations":"Brand-new Google accounts used for automation; Google Workspace accounts where YouTube is disabled by admin policy; tokens issued from a Google login that never visited youtube.com and accepted channel creation.","solutions":["Sign in to youtube.com with the account and complete channel creation (choose handle/name).","Re-authenticate after channel creation and retry the upload with a fresh access token.","Verify with the API: channels.list(part=snippet, mine=true) returns at least one item before uploading.","For Workspace accounts, ask the admin to enable YouTube service, or use a personal Google account."],"exampleFix":"// before\nawait youtubeService.uploadVideo(accountIdWithoutChannel, file);\n// after\nconst channels = await youtube.channels.list({ part: ['snippet'], mine: true, auth: oauth2Client });\nif (!channels.data.items?.length) throw new Error('Create a YouTube channel for this account first');\nawait youtubeService.uploadVideo(accountId, file);","handlingStrategy":"try-catch","validationCode":"const ch = await fetch('https://www.googleapis.com/youtube/v3/channels?part=snippet&mine=true', { headers: { Authorization: `Bearer ${token}` } });\nconst chData = await ch.json();\nif (!chData.items?.length) throw new Error('Account has no YouTube channel — create one at youtube.com before uploading');","typeGuard":"function hasChannel(res: { data?: { items?: unknown[] } }): boolean {\n  return Array.isArray(res.data?.items) && res.data.items.length > 0;\n}","tryCatchPattern":"try {\n  await youtubeService.uploadVideo(accountId, file);\n} catch (e) {\n  if (String(e.message).includes('未检测到可用的 YouTube 频道')) {\n    // surface UI prompt: open youtube.com to create a channel\n  } else throw e;\n}","preventionTips":["Pre-check channels.list(mine=true) before any upload flow.","Show an onboarding step 'create your YouTube channel' after linking an account.","Detect reason youtubeSignupRequired early at account-link time, not upload time.","For Workspace accounts, verify YouTube is enabled by admin policy."],"tags":["youtube-api","oauth","missing-channel","precondition"],"backgroundTag":"youtube-channel-not-found","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}