Skip to content

fix(adagents): raise AdagentsAccessBlockedError on 403 + cf-mitigated: challenge#837

Draft
bokelley wants to merge 2 commits into
mainfrom
claude/issue-801-bot-mitigation-error-v2
Draft

fix(adagents): raise AdagentsAccessBlockedError on 403 + cf-mitigated: challenge#837
bokelley wants to merge 2 commits into
mainfrom
claude/issue-801-bot-mitigation-error-v2

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

Closes #801.

When _fetch_adagents_url receives HTTP 403 with cf-mitigated: challenge, it now raises AdagentsAccessBlockedError (an AdagentsValidationError subclass) instead of the generic AdagentsValidationError. This makes the Cloudflare bot-challenge case distinguishable in application code without breaking existing except AdagentsValidationError handlers.

Changes

  • src/adcp/exceptions.py — new AdagentsAccessBlockedError(AdagentsValidationError) with publisher_domain attribute and actionable suggestion text
  • src/adcp/adagents.py — 403 + cf-mitigated: challenge guard inserted in _fetch_adagents_url between the 404 and generic non-200 checks; fetch_adagents docstring Raises section updated; explanatory comments added at swallow sites
  • src/adcp/__init__.pyAdagentsAccessBlockedError added to exports and __all__
  • tests/test_adagents.py — four new tests: CF-mitigated 403 raises the subclass (parametrized for challenge/Challenge casing), plain 403 does not, subclass is catchable as AdagentsValidationError
  • tests/fixtures/public_api_snapshot.jsonAdagentsAccessBlockedError added alphabetically

Design notes

  • Inherits from AdagentsValidationError (not ADCPError directly) — existing except AdagentsValidationError call sites catch it automatically; no call-site patches required
  • Only fires when both conditions hold: status 403 and cf-mitigated: challenge header present (case-insensitive, OWS-stripped); plain 403s still raise the generic error
  • Non-breaking: all existing exception handling continues to work
  • AdagentsAccessBlockedError is intentionally swallowed in _try_managerdomain_fallback and fetch_agent_authorizations (treated as authorization-unavailable, same as a missing file); comments added to each site
  • validate_adagents_domain surfaces the error via str(e) in AdAgentsValidationResult.errors — the actionable message reaches callers

What was tested

  • pytest tests/test_adagents.py -v — 192 passed
  • pytest tests/ (excluding pre-existing TLS network test) — 5021 passed, 35 skipped
  • mypy src/adcp/adagents.py src/adcp/exceptions.py src/adcp/__init__.py — no issues
  • ruff check — no issues

Pre-PR review

  • code-reviewer: approved — guard condition and exception hierarchy correct; blocker (missing Challenge-casing test) fixed; intentional-swallow sites commented
  • dx-expert: approved — inheritance hierarchy is correct for back-compat; guard condition is tight; error message and suggestion text are actionable; publisher_domain attribute is a DX improvement

Known nit (not fixed in this PR): AdagentsNotFoundError and AdagentsTimeoutError do not store publisher_domain as an instance attribute; AdagentsAccessBlockedError does. Backfilling those siblings is a separate, additive change.

Triage-managed PR. This bot does not currently iterate on
review comments or PR conversation threads (only on the source
issue). To unblock:

  • Push fixup commits directly: gh pr checkout <num>
    fix → push.
  • Or re-trigger: comment /triage execute on the source
    issue.

See adcp#3121
for context.

Session: https://claude.ai/code/cse_01HBuAdZK8P2nCiEGqAeJ2wj


Generated by Claude Code

claude added 2 commits May 23, 2026 21:44
…: challenge

When _fetch_adagents_url receives HTTP 403 with cf-mitigated: challenge,
raise AdagentsAccessBlockedError (AdagentsValidationError subclass) so
callers can distinguish Cloudflare bot-management blocks from other errors.
Existing except AdagentsValidationError handlers catch it automatically.

Closes #801
- Add parametrized test for capitalized cf-mitigated: Challenge (Cloudflare's actual casing)
- Add .strip() to header comparison for OWS robustness
- Document AdagentsAccessBlockedError in fetch_adagents Raises section
- Add explanatory comments at sites that intentionally swallow the subclass
Comment thread tests/test_adagents.py
err = AdagentsAccessBlockedError("cafemedia.com")
assert isinstance(err, AdagentsValidationError)
assert "cf-mitigated: challenge" in str(err)
assert "cafemedia.com" in str(err)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(adagents): cafemedia.com (Raptive AAO file) blocks SDK with HTTP 403 — Cloudflare challenge on httpx client fingerprint

3 participants