Skip to content

Telegram: skip global dispatcher replacement when autoSelectFamily is disabled#26890

Open
MarkShawn2020 wants to merge 3 commits intoopenclaw:mainfrom
MarkShawn2020:fix/telegram-global-dispatcher-403
Open

Telegram: skip global dispatcher replacement when autoSelectFamily is disabled#26890
MarkShawn2020 wants to merge 3 commits intoopenclaw:mainfrom
MarkShawn2020:fix/telegram-global-dispatcher-403

Conversation

@MarkShawn2020
Copy link

@MarkShawn2020 MarkShawn2020 commented Feb 25, 2026

Summary

  • Only replace the global undici dispatcher when autoSelectFamily is explicitly true
  • Previously, the dispatcher was replaced unconditionally (even with false), swapping in a bare Agent that discards the original dispatcher's configuration
  • This broke other HTTP clients sharing the same process — notably LLM provider fetches (e.g. Anthropic API) which returned HTTP 403 after the swap

Root Cause

setGlobalDispatcher(new Agent({connect: {autoSelectFamily, ...}})) creates a minimal Agent with only the autoSelectFamily connect option. The original default dispatcher may carry additional state/configuration that other HTTP clients depend on. Replacing it unconditionally causes those clients to fail.

Reproduction

  1. Configure Telegram channel with a proxy (channels.telegram.proxy)
  2. Configure Anthropic API key auth (auth.profiles.anthropic:default with type: api_key)
  3. Send a message via Telegram
  4. Observe: [agent/embedded] embedded run agent end: isError=true error=HTTP 403 forbidden: Request not allowed
  5. Disable Telegram → Anthropic works again

Fix

Only call setGlobalDispatcher() when autoSelectFamily === true (the IPv4 fallback workaround). When false or null, the default dispatcher is left untouched.

Test plan

  • Telegram + Feishu channels working simultaneously with Anthropic API key auth
  • pnpm build passes
  • Existing tests pass (pnpm testsrc/telegram/fetch.test.ts)

Fixes #23600
Related: #25682, #25676

🤖 Generated with Claude Code

Greptile Summary

Prevents unintended global undici dispatcher replacement when autoSelectFamily is false or null, fixing HTTP 403 errors in LLM provider API calls. The previous implementation unconditionally replaced the dispatcher (even with false), discarding the original dispatcher's configuration. Now only replaces when explicitly true to preserve the IPv4 fallback workaround while protecting other HTTP clients in the process.

  • Fixed condition to only replace dispatcher when autoSelectFamily === true (src/telegram/fetch.ts:50)
  • Removed redundant check and hardcoded value to true in Agent config (src/telegram/fetch.ts:51-57)
  • Updated state tracking to hardcoded true value (src/telegram/fetch.ts:62-63)

Test Impact: The test at src/telegram/fetch.test.ts:171-189 ("updates global dispatcher when autoSelectFamily decision changes") expects setGlobalDispatcher to be called twice when switching from true to false, but with this change it will only be called once. This test needs to be updated to match the new behavior.

Confidence Score: 3/5

  • Safe to merge after fixing the failing test
  • The fix correctly addresses the root cause (unconditional dispatcher replacement), and the logic change is sound. However, there's a failing test that must be updated to match the new behavior. The PR author acknowledges tests haven't been run yet.
  • src/telegram/fetch.test.ts requires test updates before merge

Last reviewed commit: 7ad40a1

(2/5) Greptile learns from your feedback when you react with thumbs up/down!

… is enabled

Replacing the global dispatcher unconditionally (even with autoSelectFamily=false)
swaps in a bare Agent that discards any configuration the original default dispatcher
carried. This breaks other HTTP clients in the same process — notably LLM provider
fetches (e.g. Anthropic API) which return HTTP 403 after the dispatcher swap.

Only replace the dispatcher when autoSelectFamily is explicitly true, which is the
only case where the workaround is actually needed.

Fixes openclaw#23600
Related: openclaw#25682, openclaw#25676

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

1 file reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 50 to 51
autoSelectDecision.value === true &&
autoSelectDecision.value !== appliedGlobalDispatcherAutoSelectFamily
Copy link
Contributor

Choose a reason for hiding this comment

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

redundant comparison on line 51 - autoSelectDecision.value is already true from line 50

Suggested change
autoSelectDecision.value === true &&
autoSelectDecision.value !== appliedGlobalDispatcherAutoSelectFamily
if (autoSelectDecision.value === true) {
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/telegram/fetch.ts
Line: 50-51

Comment:
redundant comparison on line 51 - `autoSelectDecision.value` is already `true` from line 50

```suggestion
  if (autoSelectDecision.value === true) {
```

How can I resolve this? If you propose a fix, please make it concise.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 25, 2026

Additional Comments (1)

src/telegram/fetch.ts
test will fail - expects dispatcher to be called twice when changing from true to false, but the new logic only replaces dispatcher when autoSelectFamily === true

The test expectation at line 174 (expect(setGlobalDispatcher).toHaveBeenCalledTimes(2)) will fail because the second call with autoSelectFamily: false will no longer trigger setGlobalDispatcher(). Update this test to verify that the dispatcher is NOT replaced when switching to false.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/telegram/fetch.ts
Line: 171-189

Comment:
test will fail - expects dispatcher to be called twice when changing from `true` to `false`, but the new logic only replaces dispatcher when `autoSelectFamily === true`

The test expectation at line 174 (`expect(setGlobalDispatcher).toHaveBeenCalledTimes(2)`) will fail because the second call with `autoSelectFamily: false` will no longer trigger `setGlobalDispatcher()`. Update this test to verify that the dispatcher is NOT replaced when switching to `false`.

How can I resolve this? If you propose a fix, please make it concise.

The test now verifies that switching from autoSelectFamily=true to false
does NOT replace the global dispatcher a second time.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@bmendonca3
Copy link

@MarkShawn2020 I see the intent here (avoid replacing the global dispatcher with a bare agent when autoSelectFamily is false).

One behavior concern: once autoSelectFamily=true has been applied, toggling config to false no longer restores the original/default dispatcher, so true remains sticky for the process lifetime.

Could we either (a) restore the previous dispatcher when disabled, or (b) explicitly document this sticky behavior and add a regression test for true -> false transitions?

Address review feedback: when autoSelectFamily switches from true to
false, restore the original global dispatcher instead of leaving the
replacement sticky for the process lifetime.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@MarkShawn2020
Copy link
Author

@bmendonca3 Great catch — updated in 33991d9. Now the original dispatcher is saved via getGlobalDispatcher() before the first replacement, and restored when autoSelectFamily switches back to false. Added a regression test for the true → false transition that verifies the original dispatcher is restored (not a new bare Agent).

@MarkShawn2020
Copy link
Author

The macos CI failure is unrelated to this PR — it's a pre-existing issue on main:

  • src/slack/monitor.tool-result.test.ts: TypeError: App is not a constructor (Slack SDK import issue)
  • src/auto-reply/reply/agent-runner.runreplyagent.test.ts: missing mock export for resolveAgentMainSessionKey

Neither touches telegram or the global dispatcher logic.

@openclaw-barnacle
Copy link

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle bot added the stale Marked as stale due to inactivity label Mar 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: telegram Channel integration: telegram size: S stale Marked as stale due to inactivity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Broken manual telegram configuration

2 participants