Skip to content

fix(feishu): catch thrown SDK errors for withdrawn reply targets#33515

Closed
MunemHashmi wants to merge 1 commit into
openclaw:mainfrom
MunemHashmi:fix/feishu-reply-fallback-withdrawn-target
Closed

fix(feishu): catch thrown SDK errors for withdrawn reply targets#33515
MunemHashmi wants to merge 1 commit into
openclaw:mainfrom
MunemHashmi:fix/feishu-reply-fallback-withdrawn-target

Conversation

@MunemHashmi

@MunemHashmi MunemHashmi commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Problem: The Feishu Lark SDK can throw exceptions for withdrawn/deleted reply targets (in addition to returning error codes in the response). The existing fallback only handled response-level errors, so thrown exceptions bypassed the fallback and the agent response was lost.
  • Why it matters: Users receive no reply when the target message was withdrawn before delivery — a silent failure.
  • What changed: Wrapped client.im.message.reply() in try-catch in both sendMessageFeishu and sendCardFeishu to catch thrown withdrawn/not-found errors (codes 230011, 231003) and fall back to client.im.message.create(). Extracted sendFallbackDirect helper to deduplicate the direct-send fallback block. Removed overly broad error message matching from isWithdrawnReplyError (only matches specific error codes now).
  • What did NOT change: The response-level fallback via shouldFallbackFromReplyTarget is untouched. updateCardFeishu, editMessageFeishu, and sendMarkdownCardFeishu are unaffected.

Change Type (select all)

  • Bug fix

Scope (select all touched areas)

  • Integrations

Linked Issue/PR

User-visible / Behavior Changes

Feishu replies that fail due to withdrawn/deleted target messages now automatically fall back to a direct send instead of silently failing. No config changes.

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No (replaces a failed reply with a direct send)
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Repro + Verification

Environment

  • OS: Linux
  • Runtime: Node 22+ / Bun
  • Integration/channel: Feishu

Steps

  1. Configure a Feishu account and trigger an agent reply targeting a specific message.
  2. Withdraw/delete the target message before the reply is sent.
  3. Observe that the reply falls back to a direct message send.

Expected

  • Reply falls back to client.im.message.create() and the user receives the response.

Actual (before fix)

  • SDK throws an exception, no fallback, user receives nothing.

Evidence

  • Failing test/log before + passing after

4 new tests added to send.reply-fallback.test.ts:

  • falls back to create when reply throws a withdrawn SDK error (text, .code: 230011)
  • falls back to create when card reply throws a not-found AxiosError (card, .response.data.code: 231003)
  • re-throws non-withdrawn thrown errors for text messages (.code: 99991400)
  • re-throws non-withdrawn thrown errors for card messages (.code: 99991401)

Human Verification (required)

  • Verified scenarios: All 11 tests pass (4 existing send.test.ts + 7 send.reply-fallback.test.ts)
  • Edge cases checked: SDK error shape, AxiosError shape, non-withdrawn error re-throw for both text and card paths
  • What you did not verify: Live Feishu end-to-end (no credentials available)

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: Revert the commit — the response-level fallback still works independently
  • Known bad symptoms: Unexpected fallback to direct send for errors that shouldn't trigger it (mitigated by strict code-only matching in isWithdrawnReplyError)

Risks and Mitigations

  • Risk: isWithdrawnReplyError could miss unknown SDK error shapes without .code
    • Mitigation: The response-level shouldFallbackFromReplyTarget still catches those cases when the SDK returns (doesn't throw). Code-only matching avoids false positives on unrelated thrown errors.

@openclaw-barnacle openclaw-barnacle Bot added channel: feishu Channel integration: feishu size: M labels Mar 3, 2026
@greptile-apps

greptile-apps Bot commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a silent failure in the Feishu integration where the SDK could throw an exception when a reply target message has been withdrawn or deleted. The fix wraps client.im.message.reply() in try-catch blocks in both sendMessageFeishu and sendCardFeishu, detects withdrawn/not-found errors (codes 230011, 231003) via the new isWithdrawnReplyError helper, and falls back to client.im.message.create(). Non-withdrawn thrown errors are correctly re-thrown. The logic is sound, the helper function properly checks both SDK error shapes (.code) and AxiosError shapes (.response.data.code), and the test suite validates the happy path, fallback behavior, and error re-throwing for both message types.

Confidence Score: 4/5

  • Safe to merge. The fix is targeted and well-tested; non-withdrawn errors are correctly re-thrown.
  • The PR correctly handles both error detection paths (SDK thrown errors and response-level errors) with proper re-throw logic. TypeScript's control flow ensures no uninitialized-variable risks. The implementation is backward-compatible and doesn't change the existing response-level fallback logic. The test suite validates all critical paths: fallback on withdrawn errors, non-fallback on other errors, and proper error re-throwing for both text and card message types.
  • No files require special attention; both extensions/feishu/src/send.ts and extensions/feishu/src/send.reply-fallback.test.ts are correct.

Last reviewed commit: 95f5376

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 openclaw#33496
@Takhoffman

Copy link
Copy Markdown
Contributor

Thanks again for this work.

This PR is being closed as part of an AI-assisted PR merge/triage workflow.

This landed indirectly via the synthesized PR #33789, and your contribution is credited in the changelog and as a co-author on the merge commit.

Closing this PR as superseded by #33789. If anything here looks incorrect or incomplete, reply to reopen and we can reassess.

@Takhoffman

Copy link
Copy Markdown
Contributor

Closing as superseded by #33789.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: feishu Channel integration: feishu size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Feishu reply fallback bypassed when SDK throws instead of returning error

2 participants