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
- Compress or downscale the image below 10MB before sendFile; for screenshots, convert PNG to JPEG or resize.
- In the Feishu Developer Console, confirm the bot has image-send permission and the app is published/enabled.
- Verify file.data base64 decodes to valid image bytes of the declared media_type.
- 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
- Downscale/compress images below 10MB before sendFile.
- Confirm image-send permission is granted in the Feishu console.
- Verify the base64 decodes to valid image bytes of the declared media_type.
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
- Feishu rejected the file upload for "${file.filename}" (no f
- ${action} failed: ${unwrapped.msg || unwrapped.message || `c
- Feishu WebSocket connection failed: ${error instanceof Error
- Client is not connected
- Invalid JSON from Feishu registration API: ${text.slice(0, 2
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/b3e92e9918880d2e.
Report an issue: GitHub.