Hmbown/CodeWhale · error

Lark SDK client does not expose im message create API

Error message

Lark SDK client does not expose im message create API

What it means

sendText in the Feishu bridge guards against Lark SDK shape drift: it probes client.im.v1.message.create / client.im.message.create / reply bindings, and if none of the expected im message-send functions exist on the injected Lark client it throws rather than silently failing to deliver replies.

Solutions

  1. Pin the Lark SDK version the bridge documents and reinstall node_modules so client.im.v1.message.create exists.
  2. Log the client shape (Object.keys(client.im)) to see what the installed SDK actually exposes and adapt imports to the correct package.
  3. If testing, provide a stub that includes im.v1.message.create (and reply) functions matching the real SDK surface.

Example fix

// before: partial stub in test
const client = { im: {} };
// after: stub the full surface sendText probes
const client = { im: { v1: { message: { create: async () => ({ ok: true }) } } } };
Defensive patterns

Strategy: type-guard

Validate before calling

import assert from 'node:assert';
assert(typeof client?.im?.v1?.message?.create === 'function',
  'Lark SDK client lacks im.v1.message.create — check the installed SDK version');

Type guard

function hasImCreateApi(client) {
  return typeof client?.im?.v1?.message?.create === 'function' ||
    typeof client?.im?.message?.create === 'function';
}

Try / catch

try {
  await sendText(client, config, chatId, text);
} catch (e) {
  if (String(e.message).includes('im message create API')) {
    console.error('Lark SDK version incompatible — pin the documented version.');
  }
}

Prevention

When it happens

Trigger: Constructing the bridge's message sender with a Lark client object lacking the im.v1.message.create (or legacy im.message.create) method — wrong SDK package version, a mock/test double, or a client built for a different API surface (e.g. only websocket events, no REST im namespace).

Common situations: Upgrading/downgrading @lark-base-open or lark-oapi to a version that renamed or restructured im.v1.message; passing a bot-only websocket client instead of a full API client; stubbing client.im in tests with a partial object.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/8f2e9d4293d5d13a. Report an issue: GitHub.

Appendix: source

Thrown at integrations/feishu-bridge/src/index.mjs:545

}

async function sendText(chatId, text) {
  // Try reply API first — keeps bot responses inside the same Feishu
  // thread/topic instead of spawning new standalone topics.
  // / 优先使用 reply API,确保 bot 回复留在话题群的同一条话题内。
  const state = await threadStore.getChat(chatId);
  const replyToMessageId = state?.replyToMessageId || null;

  const replyMessage =
    replyToMessageId
      ? client.im?.v1?.message?.reply?.bind(client.im.v1.message) ||
        client.im?.message?.reply?.bind(client.im.message)
      : null;
  const createMessage =
    client.im?.v1?.message?.create?.bind(client.im.v1.message) ||
    client.im?.message?.create?.bind(client.im.message);
  if (!createMessage) {
    throw new Error("Lark SDK client does not expose im message create API");
  }

  let canReply = Boolean(replyMessage);
  for (const chunk of splitMessage(text, config.maxReplyChars)) {
    const body = {
      msg_type: "text",
      content: JSON.stringify({ text: chunk })
    };
    if (canReply) {
      try {
        await replyMessage({
          path: { message_id: replyToMessageId },
          data: body
        });
        continue;
      } catch (error) {
        canReply = false;
        console.warn("Feishu reply API failed; falling back to message create", error);

View on GitHub (pinned to 433685b202)