CherryHQ/cherry-studio · error · Error

Feishu rejected the image upload for "${file.filename}" (no

Error message

Feishu rejected the image upload for "${file.filename}" (no image_key) — likely over Feishu's image size limit (~10MB) or the bot lacks image-send capability

What it means

Thrown after a successful-looking im.image.create returns no image_key. Per the in-source comment, upload endpoints return the unwrapped data object (not a {code,msg} envelope), and an HTTP 200 carrying a business error resolves to null after the SDK discards code/msg — so the adapter detects a null image_key and throws an enriched, cause-hinting error itself rather than calling ensureFeishuSuccess.

Source

Thrown at src/main/ai/channels/adapters/feishu/FeishuAdapter.ts:579

    const buffer = Buffer.from(file.data, 'base64')

    // Images go through the image API so they render inline; everything else is
    // uploaded as a generic file (`stream`) and delivered as a file message.
    //
    // NOTE: unlike `im.message.create`, the SDK's upload endpoints return the
    // unwrapped data object ({image_key} / {file_key}) — not a {code,msg,data}
    // envelope — so they must NOT go through `ensureFeishuSuccess`. Two failure
    // shapes exist: an HTTP error rejects (the http instance surfaces status +
    // detail), while an HTTP 200 carrying a business error (code != 0, e.g. an
    // oversize image) resolves to null after the SDK discards code/msg — so for
    // that path we log and throw an enriched, cause-hinting error ourselves.
    if (file.media_type.startsWith('image/')) {
      const uploaded = await this.client.im.image.create({ data: { image_type: 'message', image: buffer } })
      const imageKey = uploaded?.image_key
      if (!imageKey) {
        this.log.warn('Feishu image upload returned no image_key', { chatId, filename: file.filename, size: file.size })
        throw new Error(
          `Feishu rejected the image upload for "${file.filename}" (no image_key) — likely over Feishu's image size limit (~10MB) or the bot lacks image-send capability`
        )
      }

      ensureFeishuSuccess(
        await this.client.im.message.create({
          params: { receive_id_type: 'chat_id' },
          data: { receive_id: chatId, msg_type: 'image', content: JSON.stringify({ image_key: imageKey }) }
        }),
        'Send Feishu image'
      )
    } else {
      const uploaded = await this.client.im.file.create({
        data: { file_type: 'stream', file_name: file.filename, file: buffer }
      })
      const fileKey = uploaded?.file_key
      if (!fileKey) {
        this.log.warn('Feishu file upload returned no file_key', { chatId, filename: file.filename, size: file.size })

View on GitHub (pinned to 726446b54c)

Solutions

  1. Compress or downscale the image below 10MB before sendFile; for screenshots, convert PNG to JPEG or resize.
  2. In the Feishu Developer Console, confirm the bot has image-send permission and the app is published/enabled.
  3. Verify file.data base64 decodes to valid image bytes of the declared media_type.
  4. If the cause is transient, retry image upload once before surfacing the error.

Example fix

// before
if (!imageKey) {
  this.log.warn('Feishu image upload returned no image_key', { chatId, filename: file.filename, size: file.size })
  throw new Error(`Feishu rejected the image upload for "${file.filename}" (no image_key) ...`)
}

// after — fall back to a file message so delivery still succeeds
if (!imageKey) {
  this.log.warn('Feishu image upload returned no image_key; falling back to file send', { chatId, filename: file.filename, size: file.size })
  return this.sendFileAsGeneric(chatId, file)
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate size before upload.
function isWithinFeishuImageLimit(file: FileAttachment): boolean {
  const bytes = Math.ceil((file.data.length * 3) / 4) // base64 -> bytes
  return file.media_type.startsWith('image/') && bytes <= 10 * 1024 * 1024
}

Type guard

function isFeishuImageRejected(e: unknown): e is Error {
  return e instanceof Error && e.message.startsWith('Feishu rejected the image upload')
}

Try / catch

try {
  await feishu.sendFile(chatId, file)
} catch (e) {
  if (isFeishuImageRejected(e)) {
    await feishu.sendMessage(chatId, `[image too large to upload: ${file.filename}]`)
    return
  }
  throw e
}

Prevention

When it happens

Trigger: file.media_type starts with 'image/', client.im.image.create resolves but uploaded.image_key is undefined/null/empty. The adapter logs a warn with chatId/filename/size then throws.

Common situations: Image over Feishu's ~10MB image limit, bot lacking the im:message:send_as_bot / image-send capability, corrupted/invalid image bytes, or a transient upload error the SDK swallowed.

Related errors


AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12). Data as JSON: /api/errors/b3e92e9918880d2e. Report an issue: GitHub.