Skip to content

Feishu typing indicator ignores 429/quota errors, causing infinite retry loop #28062

@guoqunabc

Description

@guoqunabc

Bug Description / 问题描述

EN: When the Feishu (Lark) API monthly quota is exceeded (HTTP 429 / error code 99991403), the typing indicator keepalive loop continues retrying indefinitely every 3 seconds, generating tens of thousands of failed API calls.

中文: 当飞书 API 月度配额用尽时(HTTP 429 / 错误码 99991403),typing indicator 的 keepalive 循环不会停止,每3秒持续重试,产生数万次无效 API 调用。

Root Cause / 根因分析

In extensions/feishu/src/typing.ts, addTypingIndicator catches all errors and silently returns without throwing:

extensions/feishu/src/typing.ts 中,addTypingIndicator 捕获了所有异常并静默返回,不向上抛出:

} catch (err) {
    // Silently fail - typing indicator is not critical
    console.log(`[feishu] failed to add typing indicator: ${err}`);
    return { messageId, reactionId: null };
}

The core createTypingCallbacks circuit breaker (maxConsecutiveFailures: 2) relies on start() throwing to detect failures and trip the breaker. Since errors are swallowed, the breaker never trips, and the keepalive loop retries forever.

核心层的 createTypingCallbacks 断路器(maxConsecutiveFailures: 2)依赖 start() 抛出异常来检测失败并触发熔断。由于异常被吞掉,断路器永远不会触发,keepalive 循环无限重试。

Impact / 影响

After the quota was hit:

  • ~4,800 failed typing API calls per hour (multiple concurrent sessions × keepalive interval)
  • 76,000+ total 429 errors accumulated in ~8 hours before manual intervention
  • Worsens quota exhaustion if limits are call-count based

配额耗尽后:

  • 每小时约 4,800 次失败的 typing API 调用(多个并发会话 × keepalive 间隔)
  • 约8小时内累计 76,000+ 次 429 错误(手动干预前)
  • 如果配额按调用次数计算,会加速配额消耗

Suggested Fix / 建议修复

Re-throw rate-limit / quota errors so the circuit breaker can trip. Other non-critical errors can remain silently handled:

对 429/配额超限错误向上抛出,让断路器正常熔断。其他非关键错误仍静默处理:

} catch (err) {
    const status = (err as any)?.response?.status;
    const code = (err as any)?.response?.data?.code;
    if (status === 429 || code === 99991403) {
        console.log(`[feishu] typing indicator rate-limited, propagating to circuit breaker`);
        throw err;
    }
    // Silently fail for other non-critical errors
    console.log(`[feishu] failed to add typing indicator: ${err}`);
    return { messageId, reactionId: null };
}

The same pattern should arguably apply to removeTypingIndicator as well.
同样的逻辑也建议应用到 removeTypingIndicator

Environment / 环境

  • OpenClaw: 2026.2.26
  • Feishu plugin (free-tier app, default monthly API quota)
  • Trigger: Monthly API call quota exceeded (error 99991403)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions