{"record":{"id":"71d76139f5c3ff6b","repo":"yikart/AiToEarn","slug":"youtube-71d761","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":691,"sourceCode":"      // 设置 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,\n          description: description,\n          // tags: keywords ? keywords.split(',') : [],\n          tags: keywords ? keywords : [],\n          categoryId: categoryId || '22', // 默认 categoryId 为 '22'，如果没有指定\n        },\n        status: {","sourceCodeStart":673,"sourceCodeEnd":709,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-electron/server/src/modules/plat/youtube/youtube.service.ts#L673-L709","documentation":"In uploadVideo's catch block around channels.list(mine=true), when Google rejects the request with error reason 'youtubeSignupRequired', the service rethrows this friendlier Error. It means the authenticated Google account is not enrolled with YouTube at all — YouTube features (including the Data API) are unavailable for that identity until a channel exists.","triggerScenarios":"Any upload attempt where the channels.list probe (or the upload itself) returns err.errors[0].reason === 'youtubeSignupRequired'; typically accounts created via Google sign-up that never activated YouTube.","commonSituations":"Google Workspace/enterprise accounts with YouTube disabled; freshly created service-adjacent Google accounts; users switching the linked account in the app to one that has no YouTube presence.","solutions":["Open youtube.com with the exact linked Google account and finish channel creation, then retry the upload.","Re-authorize the account in the app after activation so scopes/token are refreshed.","Confirm via GET https://www.googleapis.com/youtube/v3/channels?part=snippet&mine=true that items is non-empty.","If it is a Workspace account, have the admin enable YouTube or link a personal account instead."],"exampleFix":"// before\n// upload attempted directly with a non-YouTube Google identity\n// after\nconst res = await fetch('https://www.googleapis.com/youtube/v3/channels?part=snippet&mine=true', { headers: { Authorization: `Bearer ${token}` } });\nconst data = await res.json();\nif (!data.items?.length) throw new Error('Enable YouTube / create a channel for this Google account first');","handlingStrategy":"validation","validationCode":"const res = await fetch('https://www.googleapis.com/youtube/v3/channels?part=snippet&mine=true', { headers: { Authorization: `Bearer ${token}` } });\nconst body = await res.json();\nconst reason = body?.error?.errors?.[0]?.reason;\nif (reason === 'youtubeSignupRequired') throw new Error('YouTube not enabled for this Google account');","typeGuard":"function isSignupRequired(err: { errors?: { reason?: string }[] }): boolean {\n  return err.errors?.[0]?.reason === 'youtubeSignupRequired';\n}","tryCatchPattern":"try {\n  await upload();\n} catch (e) {\n  if (isSignupRequired(e) || String(e.message).includes('当前账号未启用 YouTube')) {\n    redirectToYouTubeChannelCreation();\n  } else throw e;\n}","preventionTips":["Validate YouTube enrollment immediately after OAuth link, before any upload.","Distinguish youtubeSignupRequired from other 403 reasons in handling code.","Prefer personal Google accounts for automation when Workspace blocks YouTube.","Re-auth after the user creates a channel so scopes reflect the new state."],"tags":["youtube-api","oauth","youtube-signup-required","account-not-enabled"],"backgroundTag":"youtube-signup-required","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}