{"record":{"id":"af337c8c9a19d895","repo":"CherryHQ/cherry-studio","slug":"action-failed-unwrapped-msg-unwrapped-mes","errorCode":null,"errorMessage":"${action} failed: ${unwrapped.msg || unwrapped.message || `code=${String(unwrapped.code)}`}","messagePattern":"(.+?) failed: (.+?)`\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/channels/adapters/feishu/FeishuAdapter.ts","lineNumber":91,"sourceCode":"    typeof response === 'object' &&\n    'data' in response &&\n    response.data &&\n    typeof response.data === 'object' &&\n    'code' in response.data\n  ) {\n    return response.data as FeishuApiResponse<T>\n  }\n\n  return { code: -1, msg: 'Unexpected Feishu API response' }\n}\n\nfunction ensureFeishuSuccess<T>(response: unknown, action: string): FeishuApiResponse<T> {\n  const unwrapped = unwrapFeishuResponse<T>(response)\n  if (unwrapped.code === 0) {\n    return unwrapped\n  }\n\n  throw new Error(`${action} failed: ${unwrapped.msg || unwrapped.message || `code=${String(unwrapped.code)}`}`)\n}\n\n/**\n * Build a Feishu \"post\" message payload with markdown element.\n * Feishu's post format with md tag renders markdown natively.\n */\nfunction buildPostPayload(text: string): string {\n  return JSON.stringify({\n    zh_cn: {\n      content: [[{ tag: 'md', text }]]\n    }\n  })\n}\n\nconst STREAMING_ELEMENT_ID = 'streaming_content'\n\n/** Throttle interval for CardKit streaming updates (ms). */\nconst CARDKIT_THROTTLE_MS = 200","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/channels/adapters/feishu/FeishuAdapter.ts#L73-L109","documentation":"Thrown by ensureFeishuSuccess() when a Feishu (Lark) API response envelope has a non-zero business code. Feishu returns HTTP 200 with {code,msg,data}; code 0 means success, anything else is a business error. The message concatenates the action label plus msg/message/code from the envelope. unwrapFeishuResponse also synthesizes code:-1 if the shape is unexpected.","triggerScenarios":"Any client.im.* call routed through ensureFeishuSuccess — e.g. sendRawMessage's client.im.message.create (line ~543), sendFile's image/file message.create (lines ~588/606) — where the resolved envelope code !== 0. Also fires when the SDK returns a non-envelope object, yielding the synthetic 'Unexpected Feishu API response' / code=-1.","commonSituations":"chat_id/receive_id is wrong or the bot was removed from the chat, tenant_access_token expired or app permissions (im:message:send_as_bot) not granted, post content JSON malformed, sending to a chat type not enabled for the app, or SDK version returning a shape the unwrap helper doesn't recognize.","solutions":["Read the embedded msg — Feishu error messages are specific (e.g. '230002 chat_id is invalid', '99991663 token is invalid', '230001 permission denied'). Map it to the matching fix.","Verify the bot app has the required scopes (im:message, im:message:send_as_bot) and that it was added to the target group; re-add it if removed.","If code=-1 with 'Unexpected Feishu API response', the SDK returned a non-envelope object — check the @larksuiteoapi/node-sdk version and that you are not passing an upload result (which is already unwrapped) into ensureFeishuSuccess.","Refresh tenant_access_token (the SDK normally auto-refreshes; confirm appId/appSecret are correct so refresh can succeed)."],"exampleFix":"// before\nthrow new Error(`${action} failed: ${unwrapped.msg || unwrapped.message || `code=${String(unwrapped.code)}`}`)\n\n// after — include code separately for programmatic matching and keep data for context\nthrow new Error(`${action} failed [code=${unwrapped.code}]: ${unwrapped.msg || unwrapped.message || 'unknown'}`, { cause: unwrapped })","handlingStrategy":"try-catch","validationCode":"// Validate the receive_id format before calling the IM API.\nfunction isValidFeishuChatId(id: string): boolean {\n  return /^oc_[a-zA-Z0-9]+$/.test(id)\n}","typeGuard":"interface FeishuApiResponse<T> { code: number; msg?: string; message?: string; data?: T }\nfunction isFeishuBusinessError(e: unknown): e is Error {\n  return e instanceof Error && /failed:/.test(e.message) && !e.message.includes('HTTP')\n}","tryCatchPattern":"try {\n  await feishu.sendMessage(chatId, text)\n} catch (e) {\n  if (isFeishuBusinessError(e)) {\n    if (/invalid|not exist/.test(e.message)) return // drop message to deleted chat\n    if (/token/i.test(e.message)) await feishu.refreshToken()\n  }\n  throw e\n}","preventionTips":["Confirm the bot is a member of the target chat and has im:message:send_as_bot scope before sending.","Keep @larksuiteoapi/node-sdk on a tested version so the response envelope shape stays stable.","Never route upload-endpoint results (already unwrapped) through ensureFeishuSuccess."],"tags":["feishu","lark","api-envelope","permissions","business-error"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}