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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions