mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-26 17:08:43 +00:00
fix(feishu): catch thrown SDK errors for withdrawn reply targets
The Feishu Lark SDK can throw exceptions (SDK errors with .code or AxiosErrors with .response.data.code) for withdrawn/deleted reply targets, in addition to returning error codes in the response object. Wrap reply calls in sendMessageFeishu and sendCardFeishu with try-catch to handle thrown withdrawn/not-found errors (230011, 231003) and fall back to client.im.message.create, matching the existing response-level fallback behavior. Also extract sendFallbackDirect helper to deduplicate the direct-send fallback block across both functions. Closes #33496
This commit is contained in:
@@ -102,4 +102,78 @@ describe("Feishu reply fallback for withdrawn/deleted targets", () => {
|
||||
|
||||
expect(createMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("falls back to create when reply throws a withdrawn SDK error", async () => {
|
||||
const sdkError = Object.assign(new Error("request failed"), { code: 230011 });
|
||||
replyMock.mockRejectedValue(sdkError);
|
||||
createMock.mockResolvedValue({
|
||||
code: 0,
|
||||
data: { message_id: "om_thrown_fallback" },
|
||||
});
|
||||
|
||||
const result = await sendMessageFeishu({
|
||||
cfg: {} as never,
|
||||
to: "user:ou_target",
|
||||
text: "hello",
|
||||
replyToMessageId: "om_parent",
|
||||
});
|
||||
|
||||
expect(replyMock).toHaveBeenCalledTimes(1);
|
||||
expect(createMock).toHaveBeenCalledTimes(1);
|
||||
expect(result.messageId).toBe("om_thrown_fallback");
|
||||
});
|
||||
|
||||
it("falls back to create when card reply throws a not-found AxiosError", async () => {
|
||||
const axiosError = Object.assign(new Error("Request failed"), {
|
||||
response: { status: 200, data: { code: 231003, msg: "The message is not found" } },
|
||||
});
|
||||
replyMock.mockRejectedValue(axiosError);
|
||||
createMock.mockResolvedValue({
|
||||
code: 0,
|
||||
data: { message_id: "om_axios_fallback" },
|
||||
});
|
||||
|
||||
const result = await sendCardFeishu({
|
||||
cfg: {} as never,
|
||||
to: "user:ou_target",
|
||||
card: { schema: "2.0" },
|
||||
replyToMessageId: "om_parent",
|
||||
});
|
||||
|
||||
expect(replyMock).toHaveBeenCalledTimes(1);
|
||||
expect(createMock).toHaveBeenCalledTimes(1);
|
||||
expect(result.messageId).toBe("om_axios_fallback");
|
||||
});
|
||||
|
||||
it("re-throws non-withdrawn thrown errors for text messages", async () => {
|
||||
const sdkError = Object.assign(new Error("rate limited"), { code: 99991400 });
|
||||
replyMock.mockRejectedValue(sdkError);
|
||||
|
||||
await expect(
|
||||
sendMessageFeishu({
|
||||
cfg: {} as never,
|
||||
to: "user:ou_target",
|
||||
text: "hello",
|
||||
replyToMessageId: "om_parent",
|
||||
}),
|
||||
).rejects.toThrow("rate limited");
|
||||
|
||||
expect(createMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("re-throws non-withdrawn thrown errors for card messages", async () => {
|
||||
const sdkError = Object.assign(new Error("permission denied"), { code: 99991401 });
|
||||
replyMock.mockRejectedValue(sdkError);
|
||||
|
||||
await expect(
|
||||
sendCardFeishu({
|
||||
cfg: {} as never,
|
||||
to: "user:ou_target",
|
||||
card: { schema: "2.0" },
|
||||
replyToMessageId: "om_parent",
|
||||
}),
|
||||
).rejects.toThrow("permission denied");
|
||||
|
||||
expect(createMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user