Baike.dev
All toolsAI codingTrendingOpen sourceNewsSubmit
Log in
Back to tool/Back to issues
#685·Agent-Reach

doctor reports web channel "ok" while Jina Reader is unreachable — false positive

Author: saber4231Created Sep 11, 2026Updated Sep 11, 2026

Summary

WebChannel.check() returns ok unconditionally, so agent-reach doctor advertises the tier-0 catch-all web channel as available on networks where r.jina.ai cannot be reached at all. read() then fails for every URL — the report is a false positive that sends the agent down a dead path.

Same class as #623 (exa_search reported ok while the MCP server was not configured).

Environment where it bites

Mainland China, no proxy:

$ curl -s -o /dev/null -w "%{http_code}\n" https://r.jina.ai/
000

r.jina.ai resolves to 2a03:2880:f136:83:face:b00c:0:25de (a Facebook range) and 103.39.76.66; both TCP connects time out. That is DNS poisoning, not a slow network, so no amount of retrying helps.

agent-reach doctor still printed:

✅ 任意网页 — 通过 Jina Reader 读取任意网页(curl https://r.jina.ai/URL)

With a proxy enabled the same machine reads fine (read() returns in ~1.2s), so this is purely the check not reflecting reality.

Root cause

agent_reach/channels/web.py:

def check(self, config=None):
    # 恒可用兜底渠道:无本地命令、不做网络探测(doctor 已有多个渠道触网),保持零开销
    self.active_backend = self.backends[0]
    return "ok", "通过 Jina Reader 读取任意网页(curl https://r.jina.ai/URL)"

Meanwhile base.py states the contract:

shutil.which() alone is NOT proof of health [...] Channels should really execute a lightweight command before claiming a backend active. Subclasses with external backends must really probe them [...] and set self.active_backend.

Jina Reader is an external backend, so web is currently the one channel claiming an active backend without probing it.

Proposed fix

Probe the reader in check() and report warn with active_backend = None when unreachable, pointing at the Exa backend as the fallback read path.

The probe is a GET of the reader root that reads a single byte. Measured on a healthy (proxied) network: ~0.1s. On an unreachable network it is bounded by the socket timeout.

The probe must be a GET. A HEAD to the root is held open by Cloudflare until the socket times out, which reports a working reader as unreachable — I hit exactly that while testing this.

The awkward part (maintainer call)

tests/test_web_channel.py currently asserts the opposite, and the module docstring calls it out explicitly:

def test_check_is_ok_and_touches_no_network():
    ...
    # The fallback channel must stay zero-overhead: no probing on check().
    mock_open.assert_not_called()

So this reverses a deliberate, test-enforced decision rather than fixing an oversight. I have a PR ready that flips that test to cover both the reachable and unreachable paths — but if zero-overhead is a hard requirement, an alternative is to gate the probe behind a config key or a doctor --probe flag and keep the default behaviour. Happy to rework it either way.

Source: Panniantong/Agent-Reach

View original on GitHubView discussion on GitHub