CherryHQ/cherry-studio · error · Error

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

Error message

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

What it means

Companion to 105 for the generic-file branch: client.im.file.create with file_type 'stream' returns no file_key. Same unwrapped-data contract — a null file_key means the upload silently failed, so the adapter throws an enriched error instead of routing through ensureFeishuSuccess.

Source

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

          `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 })
        throw new Error(
          `Feishu rejected the file upload for "${file.filename}" (no file_key) — likely over Feishu's file size limit (~30MB) or the bot lacks file-send capability`
        )
      }

      ensureFeishuSuccess(
        await this.client.im.message.create({
          params: { receive_id_type: 'chat_id' },
          data: { receive_id: chatId, msg_type: 'file', content: JSON.stringify({ file_key: fileKey }) }
        }),
        'Send Feishu file'
      )
    }

    this.log.info('Sent file', { chatId, filename: file.filename, size: file.size, mediaType: file.media_type })
  }

  async sendTypingIndicator(chatId: string): Promise<void> {
    await this.setChatReaction(chatId, REACTION_THINKING)

View on GitHub (pinned to 726446b54c)

Solutions

  1. Keep attachments under ~30MB; chunk or host large files externally and send a link instead.
  2. Confirm the bot has file-send permission in the Feishu console.
  3. Sanitize file.filename (ASCII-safe, no path separators) before upload.
  4. Retry once on a null file_key for transient upload failures.
Defensive patterns

Strategy: validation

Validate before calling

// Validate size before upload.
function isWithinFeishuFileLimit(file: FileAttachment): boolean {
  const bytes = Math.ceil((file.data.length * 3) / 4)
  return bytes <= 30 * 1024 * 1024
}

Type guard

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

Try / catch

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

Prevention

When it happens

Trigger: Non-image file path: file.media_type does not start with 'image/', client.im.file.create resolves but uploaded.file_key is undefined/null/empty. Logged with chatId/filename/size, then thrown.

Common situations: File over Feishu's ~30MB file limit, bot lacking file-send capability, invalid file bytes, or filename containing characters the SDK rejects.

Related errors


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