feat(xhs): add AccountRestrictedError + upgrade 300011 raise sites (F001)#416
Conversation
Subclass of ChannelAuthError so the existing fallback chain treats it the same way (switch to next method), but the host agent surface gets a more actionable message. Used by upcoming XHS account-restriction detection (plan F001 S1).
Plan F001 S1 — covers (a) subclass relationship to ChannelAuthError + PermanentError, (b) message preservation via str(exc).
…hError Both 300011 raise sites in via_signsrv (the inline-300011 branch and the empty-results probe branch) now raise the more precise AccountRestrictedError type. AccountRestrictedError is a subclass of ChannelAuthError so the existing fallback chain still treats it as a recoverable auth failure (switches to via_tikhub) — but downstream surfaces can now distinguish 'account flagged' from 'missing/expired credentials'. Plan F001 path B (advisor-confirmed minimal scope after discovering the mitigation was already implemented inline).
- Existing test renamed + assertion upgraded to AccountRestrictedError. - New test_xhs_signsrv_empty_search_with_me_300011_is_account_restricted_subclass proves the raised exception is BOTH AccountRestrictedError AND ChannelAuthError, so the fallback chain still recognizes it.
Mitigation block now describes the actual behavior: empty-results probe + AccountRestrictedError raise. AccountRestrictedError is a subclass of ChannelAuthError so the fallback chain still recognizes it.
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 5 minutes and 33 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Introduces a more specific typed auth failure for Xiaohongshu (XHS) account restriction (code=300011) so downstream surfaces can distinguish “account flagged” from generic authentication failures while preserving the existing fallback-chain behavior.
Changes:
- Added
AccountRestrictedError(ChannelAuthError)to represent upstream account-restriction/flagged states. - Updated XHS
via_signsrvto raiseAccountRestrictedErrorat the twocode=300011detection sites. - Updated XHS skill documentation and unit tests to reflect/validate the new exception type.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
autosearch/channels/base.py |
Adds the new AccountRestrictedError exception type as a ChannelAuthError subclass. |
autosearch/skills/channels/xiaohongshu/methods/via_signsrv.py |
Switches code=300011 raises from ChannelAuthError to AccountRestrictedError. |
autosearch/skills/channels/xiaohongshu/SKILL.md |
Updates the “Known Issue” mitigation notes to reflect the implemented detection + new exception type. |
tests/unit/test_xhs_signsrv_account_restriction.py |
Updates the existing test to expect AccountRestrictedError and adds a subclass-invariant test. |
tests/unit/test_channels_base.py |
Adds unit tests asserting subclass relationships and message preservation for AccountRestrictedError. |
| """Raised when a search returned no results because the account itself | ||
| is flagged/restricted upstream (e.g. XHS code=300011), distinct from a | ||
| generic ChannelAuthError (which means missing/expired credentials). The | ||
| fallback chain treats both the same -- switch to the next method -- but | ||
| the host agent surface gets a more actionable message.""" |
There was a problem hiding this comment.
The AccountRestrictedError docstring says this is raised when a search returned no results, but via_signsrv.search() also raises it on the explicit code=300011 response path (not necessarily empty results). Please update the docstring to describe the broader contract (account restriction signaled by upstream, including the direct 300011 response case) to avoid misleading future consumers.
| """Raised when a search returned no results because the account itself | |
| is flagged/restricted upstream (e.g. XHS code=300011), distinct from a | |
| generic ChannelAuthError (which means missing/expired credentials). The | |
| fallback chain treats both the same -- switch to the next method -- but | |
| the host agent surface gets a more actionable message.""" | |
| """Raised when the upstream signals the account itself is | |
| flagged/restricted (e.g. XHS code=300011), including explicit | |
| account-restriction responses and cases that may surface as an empty | |
| search result. Distinct from a generic ChannelAuthError (which means | |
| missing/expired credentials). The fallback chain treats both the same | |
| -- switch to the next method -- but the host agent surface gets a more | |
| actionable message.""" |
| # code=300011: XHS account flagged. Surface as AccountRestrictedError so the | ||
| # user sees "your XHS account is restricted, run autosearch login xhs" | ||
| # rather than a confusing empty result. | ||
| if xhs_code == 300011: | ||
| from autosearch.channels.base import ChannelAuthError | ||
| from autosearch.channels.base import AccountRestrictedError | ||
|
|
||
| LOGGER.warning( | ||
| "xhs_account_restricted", | ||
| reason="XHS account flagged (code=300011). Run 'autosearch login xhs' with a normal account.", | ||
| ) | ||
| raise ChannelAuthError( | ||
| raise AccountRestrictedError( | ||
| "XHS account flagged (code=300011). " | ||
| "Run 'autosearch login xhs' with a normal account." | ||
| ) |
There was a problem hiding this comment.
The new AccountRestrictedError raise on the direct xhs_code == 300011 path isn’t covered by the current unit tests (the existing tests only exercise the empty-results + /user/me probe path). Please add a test that simulates the XHS search response returning {"code": 300011, ...} and asserts AccountRestrictedError is raised, so both upgraded raise sites are locked in.
* docs(security): add P0 deep-scan report from 2026-04-26 6-agent scan Source-of-truth artifact for the autosearch-0426-p0-deep-scan-fix plan. Lists 6 P0 findings; P0-5 (release.yml strong gate) was already fixed in PR #414, so the active fix scope is P0-1 / P0-2 / P0-3 / P0-4 plus P0-6 hygiene. * chore(uv): sync uv.lock autosearch self-version to 2026.04.25.11 Main's uv.lock had stale autosearch version 2026.4.25.9 while pyproject already on 2026.04.25.11 (from PR #416/#417 release bumps). bump-version.sh doesn't touch uv.lock, so it drifted. Bring back into sync. Plan F001 S3 (originally planned as 'reset stale residue' — investigation showed it was a real desync fix worth committing).
Summary
AccountRestrictedError(ChannelAuthError)typed exception for the XHS account-restriction case (code=300011)raise ChannelAuthError(...)sites invia_signsrv.pyto use the more precise type — fallback chain still works (subclass ofChannelAuthError), but downstream surfaces can distinguish "account flagged" from "missing/expired credentials"SKILL.md§ Known Issue to mark mitigation as implementedBackground
Plan:
docs/exec-plans/active/autosearch-0426-xhs-account-restriction-detection.md— F001 path B.The plan author originally believed the empty-results health probe was unimplemented; we discovered (via grep + Read) that
via_signsrv.py:184-229already had the inline mitigation, just raising the genericChannelAuthError. Path B (advisor-confirmed) is the minimal-scope correction: keep S1's new precise type, upgrade the existing raise sites instead of extracting a helper just for testing's sake.Behavior preservation
AccountRestrictedErroris a subclass ofChannelAuthError. Reviewer (pr-review-toolkit:code-reviewer) verified all consumer paths:_CompiledChannel.searchfallback chain (channels/base.py:208-216) —except ChannelAuthErrorstill matches; same recoverable-error handlingcore/channel_status.py:49— maps tostatus="auth_failed",reasonfield includes class name → host agent now seesAccountRestrictedErrorinstead of genericChannelAuthErrorxueqiu/methods/api_search.py— short-circuit + priority-class logic both safe under subclassTest plan
test_channels_base.pyassertsAccountRestrictedError⊂ChannelAuthError⊂PermanentErrorand message preservationtest_xhs_signsrv_account_restriction.pyasserts raised exception isAccountRestrictedError(not just base class)test_xhs_signsrv_empty_search_with_me_300011_is_account_restricted_subclass— verifies actual instance is BOTHAccountRestrictedErrorANDChannelAuthError(locks in subclass invariant)