yikart/AiToEarn · error · TwitterPlatformException

Twitter media id missing

Error message

Twitter media id missing

What it means

initMediaUpload starts a chunked media upload (INIT command) and reads response.data?.id as the media id. If the platform does not return a string id, TwitterPlatformException('Twitter media id missing') is thrown since subsequent APPEND/FINALIZE calls require it.

Source

Thrown at project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/twitter/twitter.service.ts:282

    const body: Media.InitializeUploadRequest = {
      mediaType: params.mediaType,
      totalBytes: params.totalBytes,
    }
    if (params.mediaCategory) {
      body.mediaCategory = params.mediaCategory
    }
    const response = await this.runApiClientOperation<{ data?: TwitterMediaUploadData }>({
      accessToken,
      endpoint: 'POST /2/media/upload/initialize',
      category: PlatformErrorCategory.MediaProcessingFailed,
      call: client => client.media.initializeUpload({
        body,
      }),
    })

    const mediaId = response.data?.id
    if (typeof mediaId !== 'string') {
      throw new TwitterPlatformException('Twitter media id missing')
    }
    return { mediaId }
  }

  async appendMediaUpload(
    accessToken: string,
    params: { mediaId: string, media: Blob, segmentIndex: number },
  ): Promise<void> {
    const formData = new FormData()
    formData.append('segment_index', String(params.segmentIndex))
    formData.append('media', params.media, 'media')

    try {
      await axios.post(
        `https://api.x.com/2/media/upload/${params.mediaId}/append`,
        formData,
        {
          headers: {

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Log the raw INIT response to inspect returned errors (e.g. 'media type not recognized')
  2. Validate media size/type against Twitter limits (images 5MB, GIF 15MB, video 512MB) before upload
  3. Ensure the client wrapper unwraps data consistently with the actual API version
  4. Retry the INIT call; transient failures can produce empty responses

Example fix

// before
const mediaId = response.data?.id
if (typeof mediaId !== 'string') {
  throw new TwitterPlatformException('Twitter media id missing')
}
// after
const mediaId = response.data?.id
if (typeof mediaId !== 'string') {
  this.logger.error(`media INIT missing id, raw=${JSON.stringify(response)}`)
  throw new TwitterPlatformException('Twitter media id missing')
}
Defensive patterns

Strategy: validation

Validate before calling

const validateMedia = (m: { buffer: Buffer; mime: string }) => {
  const limits: Record<string, number> = { 'image/jpeg': 5e6, 'image/png': 5e6, 'image/gif': 15e6, 'video/mp4': 512e6 }
  if (!limits[m.mime] || m.buffer.length > limits[m.mime]) throw new Error(`unsupported media: ${m.mime} ${m.buffer.length} bytes`)
}

Type guard

function hasMediaId(r: unknown): r is { data: { id: string } } {
  return !!r && typeof r === 'object' && typeof (r as any).data?.id === 'string'
}

Try / catch

try {
  const { mediaId } = await twitterService.initMediaUpload(accessToken, init)
} catch (e) {
  if (String(e?.message).includes('media id missing')) {
    logger.error('INIT returned no media id', { init })
  }
  throw e
}

Prevention

When it happens

Trigger: INIT upload returns success without data.id, media payload exceeds platform limits causing a soft failure, malformed upload body (invalid mediaCategory/mimeType) leading to an error response the wrapper does not surface.

Common situations: Uploading media with an unsupported category/mime combination, exceeding size limits, Twitter API contract change or client wrapper version mismatch.

Related errors


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