Skip to content

Feishu: recover from withdrawn reply targets#29980

Closed
bmendonca3 wants to merge 1 commit into
openclaw:mainfrom
bmendonca3:bm/feishu-withdrawn-reply-fallback
Closed

Feishu: recover from withdrawn reply targets#29980
bmendonca3 wants to merge 1 commit into
openclaw:mainfrom
bmendonca3:bm/feishu-withdrawn-reply-fallback

Conversation

@bmendonca3

Copy link
Copy Markdown
Contributor

Summary

Describe the problem and fix in 2–5 bullets:

  • Problem: Feishu replies treat withdrawn/deleted reply targets as terminal failures, so the final message is dropped, and typing indicator calls keep targeting the same dead message.
  • Why it matters: users can get no reply at all if they withdraw the triggering message while the agent is still processing, and the gateway keeps emitting avoidable typing-indicator failures.
  • What changed: text/card/media reply sends now fall back to a normal direct send when Feishu returns 230011/231003, typing target-gone errors now surface instead of being swallowed, and Feishu reply typing now trips immediately on the first terminal target-gone error.
  • What did NOT change (scope boundary): no routing changes, no Feishu payload format changes beyond removing reply metadata on fallback, and no non-Feishu typing behavior.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

User-visible / Behavior Changes

Feishu now falls back to a normal send when a reply target was withdrawn or deleted, and typing keepalive stops immediately for the same terminal target-gone errors.

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS: macOS 26.1
  • Runtime/container: local checkout
  • Model/provider: N/A
  • Integration/channel (if any): Feishu extension
  • Relevant config (redacted): Feishu replies enabled with standard reply-to behavior

Steps

  1. Trigger a Feishu reply that targets an existing message and then make Feishu report the target as withdrawn/deleted (230011 / 231003).
  2. Observe the reply send path and the typing indicator path while the agent is still processing.
  3. Verify whether the final message falls back to a direct send and whether typing retries keep targeting the dead message.

Expected

  • The final reply should still be delivered as a normal send without reply metadata.
  • Typing keepalive should stop immediately once Feishu says the target message is gone.

Actual

  • On upstream/main, the reply fails and is dropped, while typing-target errors are swallowed and the keepalive keeps retrying the same deleted message.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: reproduced the withdrawn-target send failure locally with a focused temporary Vitest case, reproduced the swallowed typing-target error with a second temporary Vitest case, then confirmed both pass after the fix.
  • Edge cases checked: text, cards, and media now all fall back to direct send; non-target-gone reply errors still propagate; typing still ignores other non-critical errors but now stops immediately on target-gone responses.
  • What you did not verify: live Feishu traffic against a production tenant.

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)
  • If yes, exact upgrade steps:

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: revert this commit to restore the previous reply/typing behavior.
  • Files/config to restore: extensions/feishu/src/send.ts, extensions/feishu/src/media.ts, extensions/feishu/src/typing.ts, extensions/feishu/src/reply-dispatcher.ts
  • Known bad symptoms reviewers should watch for: replies unexpectedly losing reply threading when the target still exists, or typing stopping too early on non-terminal errors.

Risks and Mitigations

  • Risk: a Feishu reply target-gone response now converts the send into a non-reply message.
    • Mitigation: the fallback is limited to Feishu’s explicit withdrawn/deleted codes, which is strictly better than dropping the reply entirely.

Verification Commands

pnpm exec vitest run /tmp/feishu-withdrawn-send-fallback-repro.test.ts /tmp/feishu-typing-target-gone-repro.test.ts --config /tmp/vitest.single-feishu-withdrawn.config.ts
pnpm exec vitest run extensions/feishu/src/send-reply-fallback.test.ts extensions/feishu/src/media.test.ts extensions/feishu/src/typing.behavior.test.ts extensions/feishu/src/typing.test.ts extensions/feishu/src/reply-dispatcher.test.ts --config /tmp/vitest.single-feishu-withdrawn.config.ts
pnpm check

pnpm check still fails on current upstream/main because of unrelated baseline typecheck errors in extensions/diagnostics-otel/src/service.ts, src/discord/voice/manager.ts, src/gateway/server-cron.ts, and src/shared/net/ip.ts.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 63af78b89c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@@ -55,6 +55,9 @@ export function createFeishuReplyDispatcher(params: CreateFeishuReplyDispatcherP

let typingState: TypingIndicatorState | null = null;
const typingCallbacks = createTypingCallbacks({
// Deleted/withdrawn reply targets should stop Feishu typing immediately
// instead of spending another keepalive interval on the same dead message.
maxConsecutiveFailures: 1,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep Feishu typing retry threshold for backoff failures

Setting maxConsecutiveFailures: 1 here trips the typing start guard on the first thrown addTypingIndicator error, not only on withdrawn/deleted-target errors. Since addTypingIndicator also throws for backoff conditions (e.g. 429, 99991400, 99991403), one transient rate-limit response now stops Feishu typing keepalive for the entire reply instead of allowing the previous one-retry grace (createTypingCallbacks defaults to 2 in src/channels/typing.ts). This widens the behavior change beyond target-gone handling and can cause user-visible loss of typing indicators under temporary throttling.

Useful? React with 👍 / 👎.

@greptile-apps

greptile-apps Bot commented Feb 28, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR implements graceful fallback handling for Feishu replies when the target message has been deleted or withdrawn. When Feishu returns error codes 230011 (message withdrawn) or 231003 (message not found), the send functions now fall back to direct sends without reply metadata instead of failing entirely. The typing indicator keepalive loop now also stops immediately on these terminal errors instead of continuing to retry the deleted message.

The implementation correctly handles both SDK response formats ({ code: 230011 }) and axios exception formats ({ response: { data: { code: 230011 } } }), with comprehensive test coverage for text, cards, images, files, and typing indicators. The maxConsecutiveFailures: 1 setting ensures typing stops on the first target-gone error.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The implementation is sound with proper error handling for both response and exception formats. Test coverage is comprehensive across all affected send paths and typing behavior. The fallback logic correctly prioritizes reply attempts before falling back to direct sends, and only applies fallback for the specific withdrawn/deleted error codes. The behavior change is strictly an improvement over the previous approach of dropping messages entirely.
  • No files require special attention

Last reviewed commit: 63af78b

@bmendonca3

Copy link
Copy Markdown
Contributor Author

Superseded by #30444 (same target issue #27103) with the refreshed branch scope.

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: L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feishu: reply silently dropped when target message is withdrawn/deleted

1 participant