openclaw - ✅(Solved) Fix `setFeishuClientRuntimeForTest` resets the SDK without clearing the client cache [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#83911Fetched 2026-05-20 03:46:53
View on GitHub
Comments
1
Participants
2
Timeline
8
Reactions
1
Timeline (top)
labeled ×5commented ×1cross-referenced ×1unsubscribed ×1

Root Cause

Reasoning

When setFeishuClientRuntimeForTest is called to swap the SDK (e.g. to inject a mock), any client already cached under a given accountId remains in clientCache. A subsequent createFeishuClient call with the same accountId and identical credentials will hit the cache and return the client that was constructed with the previous SDK instance. This can cause tests that call setFeishuClientRuntimeForTest mid-suite (or across beforeEach resets) to receive a stale client, making mock assertions unreliable. The current tests avoid this only because they mock ./client.js wholesale, but any future test that exercises the real factory is exposed.

Fix Action

Fix / Workaround

Severity: low / Confidence: medium / Category: bug Triage: risk Detected against: openclaw v2026.5.18 (latest stable at time of scan, 2026-05-18) Tooling: clawpatch 0.3.0 + acpx/claude-sonnet-4-5 via Brad Mills protocol


Standardized clawpatch finding. Persistent in v2026.5.18 (not resolved by upgrading from v2026.5.12). Finding ID: fnd_sig-feat-cli-command-1e533463a4-_0da0c6aaff.

PR fix notes

PR #84166: fix(feishu): evict client cache when SDK is swapped in tests (#83911)

Description (problem / solution / changelog)

Fixes #83911.

setFeishuClientRuntimeForTest (extensions/feishu/src/client.ts:256) swaps feishuClientSdk so tests can inject a mock Lark.Client (or other SDK piece), but the existing module-level clientCache keeps holding clients built against the previous SDK. A subsequent createFeishuClient call with the same accountId and identical credentials hits the cache and returns the stale client — the SDK swap is silently ignored from the test's perspective. Today's tests get away with it only because they mock ./client.js wholesale; any future test that exercises the real factory across SDK swaps would see stale clients and chase a phantom mock-assertion bug.

Changes

  • extensions/feishu/src/client.ts: invoke the already-defined clearClientCache() helper at the end of setFeishuClientRuntimeForTest, after the SDK swap. No new helper, no production-path change (setFeishuClientRuntimeForTest has zero production callers — it's only imported by test scaffolding).
  • extensions/feishu/src/client.test.ts: regression test that constructs a client with the default SDK, swaps to a freshly tracked replacement Client constructor via setFeishuClientRuntimeForTest, then constructs another client with the same credentials and asserts the replacement constructor (not the original) is invoked.

Diff stat: 2 files, +46 / -0.

Real behavior proof

  • Behavior or issue addressed: Sanitized issue evidence — clientCache is the module-level Map<accountId, { client, config }> at client.ts:95-108, and clearClientCache (line 248) is the existing exported helper that handles per-account and full eviction. The new line wires those two together.

  • Real environment tested: Local Node 22.x. Probe at /tmp/probe_83911.mjs (a) parses the patched client.ts and verifies clearClientCache() is called inside setFeishuClientRuntimeForTest and that the eviction follows the SDK swap (correct ordering), and (b) replays the cache + SDK swap semantics in pure JS for three scenarios — pre-fix shape (second createClient returns the stale client built against default-sdk, confirming the issue's exact symptom), patched shape (second createClient builds a fresh client with mock-sdk — the eviction works), and the production happy path (same SDK, same creds, cache hit is preserved across consecutive calls — no regression).

  • Exact steps or command run after this patch: node /tmp/probe_83911.mjs

  • Evidence after fix:

PASS: setFeishuClientRuntimeForTest now invokes clearClientCache()
PASS: cache eviction follows SDK swap (correct ordering)
PASS: replay (buggy): second createClient returns the stale client built against default-sdk — confirms #83911 root cause
PASS: replay (patched): second createClient builds a fresh client with mock-sdk — cache eviction works
PASS: replay (production, no runtime swap): cache hit preserved across consecutive calls

ALL CASES PASS
  • Observed result after fix: Tests that swap the Feishu SDK mid-suite via setFeishuClientRuntimeForTest now observe the swap on the next createFeishuClient call. Production cache-hit behavior (same SDK, same creds → reuse cached client) is unchanged because no production code invokes setFeishuClientRuntimeForTest.

  • What was not tested: Live Lark.Client construction against the Feishu SDK — that requires Feishu credentials and is outside the scope of a cache-eviction fix. The vitest regression case exercises the public createFeishuClient + setFeishuClientRuntimeForTest boundary with a tracked replacement constructor, and the probe replays both the buggy and patched shapes against the same fixture.

Audit (per CLAUDE rules — all 5 steps)

  • Existing-helper check: Reuses the already-exported clearClientCache() helper from the same file. No new helper. PASS
  • Shared-helper caller check: setFeishuClientRuntimeForTest is test-only — grep -r setFeishuClientRuntimeForTest extensions/feishu/src returns only client.ts (the implementation), client.test.ts (the import), and lifecycle.test-support.ts (a vi.fn() mock). No production caller exists; the new line cannot affect production behavior. PASS
  • Broader-fix rival scan: gh pr list --search '83911 in:title,body' and gh pr list --search 'setFeishuClientRuntimeForTest in:title,body' return no open PRs. PASS
  • Recent-merge audit: git log --oneline -5 -- extensions/feishu/src/client.ts shows e1061a8b46 test(live): tolerate provider drift in release checks — unrelated. PASS
  • Prototype-pollution scan: N/A — single Map.clear() call.

Changed files

  • extensions/feishu/src/client.test.ts (modified, +41/-0)
  • extensions/feishu/src/client.ts (modified, +5/-0)

Code Example

export function setFeishuClientRuntimeForTest(overrides?: {
  sdk?: Partial<FeishuClientSdk>;
}): void {
  feishuClientSdk = overrides?.sdk
    ? { ...defaultFeishuClientSdk, ...overrides.sdk }
    : defaultFeishuClientSdk;
}

---

const clientCache = new Map<
  string,
  {
    client: Lark.Client;
    config: { appId: string; appSecret: string; domain?: FeishuDomain; httpTimeoutMs: number };
  }
>();
RAW_BUFFERClick to expand / collapse

Severity: low / Confidence: medium / Category: bug Triage: risk Detected against: openclaw v2026.5.18 (latest stable at time of scan, 2026-05-18) Tooling: clawpatch 0.3.0 + acpx/claude-sonnet-4-5 via Brad Mills protocol

Evidence

  • extensions/feishu/src/client.ts:258-265 (setFeishuClientRuntimeForTest)
export function setFeishuClientRuntimeForTest(overrides?: {
  sdk?: Partial<FeishuClientSdk>;
}): void {
  feishuClientSdk = overrides?.sdk
    ? { ...defaultFeishuClientSdk, ...overrides.sdk }
    : defaultFeishuClientSdk;
}
  • extensions/feishu/src/client.ts:95-108 (clientCache)
const clientCache = new Map<
  string,
  {
    client: Lark.Client;
    config: { appId: string; appSecret: string; domain?: FeishuDomain; httpTimeoutMs: number };
  }
>();

Reasoning

When setFeishuClientRuntimeForTest is called to swap the SDK (e.g. to inject a mock), any client already cached under a given accountId remains in clientCache. A subsequent createFeishuClient call with the same accountId and identical credentials will hit the cache and return the client that was constructed with the previous SDK instance. This can cause tests that call setFeishuClientRuntimeForTest mid-suite (or across beforeEach resets) to receive a stale client, making mock assertions unreliable. The current tests avoid this only because they mock ./client.js wholesale, but any future test that exercises the real factory is exposed.

Reproduction

  1. Call createFeishuClient({ accountId: 'a', appId: 'x', appSecret: 'y' }) — client cached. 2. Call setFeishuClientRuntimeForTest({ sdk: mockSdk }) — SDK swapped, cache intact. 3. Call createFeishuClient({ accountId: 'a', appId: 'x', appSecret: 'y' }) — returns old client built against original SDK, not mockSdk.

Recommendation

Have setFeishuClientRuntimeForTest call clearClientCache() before returning, ensuring that any SDK swap also evicts all cached clients built with the old SDK.

Why existing tests miss this

All existing tests that use setFeishuClientRuntimeForTest or test feishu client creation mock ./client.js entirely, bypassing the real cache.

Suggested regression test

it('clears cache when SDK is replaced via setFeishuClientRuntimeForTest', () => { const c1 = createFeishuClient(creds); setFeishuClientRuntimeForTest({ sdk: mockSdk }); const c2 = createFeishuClient(creds); expect(c2).not.toBe(c1); });

Minimum fix scope

One-line change in setFeishuClientRuntimeForTest: add clearClientCache() call before or after the SDK swap.


Standardized clawpatch finding. Persistent in v2026.5.18 (not resolved by upgrading from v2026.5.12). Finding ID: fnd_sig-feat-cli-command-1e533463a4-_0da0c6aaff.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix `setFeishuClientRuntimeForTest` resets the SDK without clearing the client cache [1 pull requests, 1 comments, 2 participants]