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
- Pin the Lark SDK version the bridge documents and reinstall node_modules so client.im.v1.message.create exists.
- Log the client shape (Object.keys(client.im)) to see what the installed SDK actually exposes and adapt imports to the correct package.
- 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
- Pin the Lark SDK to the version the bridge documents in its lockfile.
- Smoke-test a real im message create against a test chat during setup.
- In tests, stub the full im.v1.message surface, not a partial client.
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
- braille-mark.py requires pillow (`pip install pillow`)
- CodeWhaleRuntimeClient requires a fetch implementation
- ${compactRuntimeError(response.status, body)}
- display enumeration needs xrandr (X11) or swaymsg/hyprctl…
- dsh is not on PATH; install the official DeepSeek Harness…
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)