CherryHQ/cherry-studio · error · Error

${action} failed: ${unwrapped.msg || unwrapped.message || `c

Error message

${action} failed: ${unwrapped.msg || unwrapped.message || `code=${String(unwrapped.code)}`}

What it means

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.

Source

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

    typeof response === 'object' &&
    'data' in response &&
    response.data &&
    typeof response.data === 'object' &&
    'code' in response.data
  ) {
    return response.data as FeishuApiResponse<T>
  }

  return { code: -1, msg: 'Unexpected Feishu API response' }
}

function ensureFeishuSuccess<T>(response: unknown, action: string): FeishuApiResponse<T> {
  const unwrapped = unwrapFeishuResponse<T>(response)
  if (unwrapped.code === 0) {
    return unwrapped
  }

  throw new Error(`${action} failed: ${unwrapped.msg || unwrapped.message || `code=${String(unwrapped.code)}`}`)
}

/**
 * Build a Feishu "post" message payload with markdown element.
 * Feishu's post format with md tag renders markdown natively.
 */
function buildPostPayload(text: string): string {
  return JSON.stringify({
    zh_cn: {
      content: [[{ tag: 'md', text }]]
    }
  })
}

const STREAMING_ELEMENT_ID = 'streaming_content'

/** Throttle interval for CardKit streaming updates (ms). */
const CARDKIT_THROTTLE_MS = 200

View on GitHub (pinned to 726446b54c)

Solutions

  1. 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.
  2. 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.
  3. 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.
  4. Refresh tenant_access_token (the SDK normally auto-refreshes; confirm appId/appSecret are correct so refresh can succeed).

Example fix

// before
throw new Error(`${action} failed: ${unwrapped.msg || unwrapped.message || `code=${String(unwrapped.code)}`}`)

// after — include code separately for programmatic matching and keep data for context
throw new Error(`${action} failed [code=${unwrapped.code}]: ${unwrapped.msg || unwrapped.message || 'unknown'}`, { cause: unwrapped })
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate the receive_id format before calling the IM API.
function isValidFeishuChatId(id: string): boolean {
  return /^oc_[a-zA-Z0-9]+$/.test(id)
}

Type guard

interface FeishuApiResponse<T> { code: number; msg?: string; message?: string; data?: T }
function isFeishuBusinessError(e: unknown): e is Error {
  return e instanceof Error && /failed:/.test(e.message) && !e.message.includes('HTTP')
}

Try / catch

try {
  await feishu.sendMessage(chatId, text)
} catch (e) {
  if (isFeishuBusinessError(e)) {
    if (/invalid|not exist/.test(e.message)) return // drop message to deleted chat
    if (/token/i.test(e.message)) await feishu.refreshToken()
  }
  throw e
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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