{"record":{"id":"f8baf6db90633892","repo":"yikart/AiToEarn","slug":"channelplatformmediaunsupported","errorCode":"ChannelPlatformMediaUnsupported","errorMessage":"YouTube publish video missing","messagePattern":"YouTube publish video missing","errorType":"exception","errorClass":"YouTubePlatformException","httpStatus":null,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/youtube/youtube-publish.provider.ts","lineNumber":116,"sourceCode":"      throw YouTubePlatformException.validation({\n        code: ResponseCode.ChannelPlatformAccountMissing,\n        category: PlatformErrorCategory.Auth,\n        context: {\n          endpoint: 'publish.channel',\n          taskId: input.taskId,\n          accountId: input.accountId,\n        },\n      })\n    }\n\n    const video = input.content.media[0]\n    if (!video) {\n      const exception = YouTubePlatformException.validation({\n        code: ResponseCode.ChannelPlatformMediaUnsupported,\n        category: PlatformErrorCategory.MediaProcessingFailed,\n        context: { endpoint: 'publish', taskId: input.taskId, accountId: input.accountId },\n      })\n      this.logger.warn(exception, 'YouTube publish video missing')\n      throw exception\n    }\n\n    const option: Partial<YoutubeOption> = input.option ?? {}\n    const privacyStatus = option.privacyStatus ?? YoutubePrivacyStatus.Public\n    await this.assertCategoryAssignable(input.credential.accessToken, option.categoryId, {\n      endpoint: 'publish.category',\n      taskId: input.taskId,\n      accountId: input.accountId,\n    })\n\n    const result = await this.youtubeService.uploadVideo(input.credential.accessToken, {\n      title: input.content.title ?? 'Untitled',\n      description: stripTopicsFromBody(input.content.body),\n      tags: parseTopicsFromBody(input.content.body),\n      privacyStatus,\n      videoUrl: video.url,\n      categoryId: option.categoryId,","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/youtube/youtube-publish.provider.ts#L98-L134","documentation":"YouTubePublishProvider.publish() throws a YouTubePlatformException (code ChannelPlatformMediaUnsupported, category MediaProcessingFailed) when the resolved media for the publish task is not a video. YouTube publishing only supports video uploads, so a missing/non-video asset aborts the task with context { endpoint: 'publish', taskId, accountId }.","triggerScenarios":"A publish task targeting YouTube whose media list has no video entry — the media was deleted before publishing, the wrong media type (image/text) was attached, or media resolution failed silently and returned undefined.","commonSituations":"Users select an image-only post and cross-post it to YouTube; media expired/cleaned up from storage between scheduling and publishing; a bug in media lookup returns the wrong asset type for the task.","solutions":["Validate at task creation/scheduling time that YouTube-bound tasks include at least one video asset","Check the task's media references still resolve (not deleted) and are typed as video before calling publish","Fix client/UI to disallow YouTube as a target for non-video content"],"exampleFix":"// before\nawait youtubePublish.publish({ taskId, accountId, media: images, ... })\n// after\nconst video = media.find((m) => m.type === MediaType.Video)\nif (!video) {\n  throw new AppException(ResponseCode.ChannelPlatformMediaUnsupported, { platform: 'youtube' })\n}\nawait youtubePublish.publish({ taskId, accountId, media: [video], ... })","handlingStrategy":"validation","validationCode":"const video = input.media?.find((m) => m.type === MediaType.Video)\nif (!video) {\n  throw new AppException(ResponseCode.ChannelPlatformMediaUnsupported, { platform: 'youtube', taskId: input.taskId })\n}","typeGuard":"function hasVideoMedia(media: Array<{ type: MediaType }> | undefined): media is [Mediatype.Media, ...MediaType.Media[]] {\n  return !!media && media.some((m) => m.type === MediaType.Video)\n}","tryCatchPattern":"try {\n  await youtubePublish.publish(input)\n} catch (err) {\n  if (err instanceof YouTubePlatformException && err.code === ResponseCode.ChannelPlatformMediaUnsupported) {\n    return failPublish(input.taskId, 'YouTube requires a video asset')\n  }\n  throw err\n}","preventionTips":["Validate media type at task creation for each target platform","Re-verify media existence right before publish (storage cleanup can delete assets)","Restrict YouTube as a selectable target to video-only compositions in the UI"],"tags":["youtube","publish","media","validation"],"backgroundTag":"unsupported-media-type","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}