fix(plugin-sdk): guard provider catalog live URL parsing against malformed responses#109986
Conversation
|
Codex review: needs maintainer review before merge. Reviewed July 17, 2026, 9:36 AM ET / 13:36 UTC. Summary PR surface: Source +32, Tests +150. Total +182 across 2 files. Reproducibility: yes. The PR provides a high-confidence loopback reproduction through the exported catalog function and production guarded-fetch stack, showing the current-main TypeError and the branch's controlled incomplete result. Review metrics: none identified. Stored data model Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land the fail-closed parsing and incomplete-pagination behavior after refreshing the branch, while preserving same-origin-only credential replay and the cursor fallback for recoverable provider responses. Do we have a high-confidence way to reproduce the issue? Yes. The PR provides a high-confidence loopback reproduction through the exported catalog function and production guarded-fetch stack, showing the current-main TypeError and the branch's controlled incomplete result. Is this the best way to solve the issue? Yes. Guarding the two external URL parsing sites inside the existing shared catalog runtime, retaining same-origin enforcement, and reporting incomplete pagination is narrower and safer than provider-specific workarounds or silent truncation. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against cc9d80c3d67e. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +32, Tests +150. Total +182 across 2 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
…ormed responses Provider catalog live discovery now wraps \ ew URL()\ calls in a \ ryParseUrl\ helper that returns undefined instead of throwing TypeError on malformed absolute URLs from API responses. Before: a malformed \ ext\ / \links.next\ URL or an unparseable fetch redirect target in the catalog response body crashes model discovery with an uncaught TypeError. After: malformed URLs are treated as absent (no next page), falling through to cursor-based pagination or completing the catalog. Co-Authored-By: Claude <[email protected]>
… has no cursor fallback When a provider catalog response advertises a next page via the `next` or `links.next` field but the URL is malformed or cross-origin, the previous fix fell through to bodyAdvertisesMoreLiveModelCatalogPages which could silently return `complete` when has_more was absent or false. This truncated catalogs that use only link-based pagination. The fix returns `incomplete` when a provider-advertised next URL is unusable and no cursor-based fallback exists, surfacing a controlled error instead of silently dropping pages. Co-Authored-By: Claude <[email protected]>
f09be4c to
7a45482
Compare
|
ClawSweeper status: review started. I am starting a fresh review of this pull request: fix(plugin-sdk): guard provider catalog live URL parsing against malformed responses This is item 1/1 in the current shard. Shard 0/1. This placeholder means the worker is alive and reading the current context. I will edit this same comment with the actual review when the claws are done clicking. Crustacean status: shell secured, claws on keyboard, evidence pebbles being sorted. |
|
Merged via squash.
|
* origin/main: (24 commits) fix(agents): keep compaction on live session model (#95713) fix(plugin-sdk): guard provider catalog live URL parsing against malformed responses (#109986) chore(cli): drop dead classifiers and single-use wrappers left by fallback removal (#112191) feat(ui): expand the lobster pet's random universe (#112073) chore(ci): audit dependency fingerprint exports (#112190) fix(ui): preserve graphemes in provider icons (#109509) fix(ui): align settings search with navigation rows (#112172) fix(agents): allow configless gateway rebind to activate standalone owner (#111841) fix(secrets): register secret targets for installed-origin plugins (#104347) improve(ui): show real machine identity in the place picker (#112162) fix: webChat scrollback history is too limited — older assistant replies and tool outputs disappear when scrolling… (#104250) test(ui): run DOM-free suites in Node (#112031) feat(nodes): make computer.act eligibility capability-based for desktop nodes (#112107) fix(apps): harden mobile gateway and watch state fix(ci): restore Z.AI API Platform validation (#112171) fix(ui): prevent Logs controls from overlapping (#112170) fix #95291: message tool fails to deliver files/images on Feishu (400 volc-dcdn / write ECONNRESET) while same Lark SDK upload succeeds standalone (#95514) refactor(cli)!: remove automatic gateway→embedded fallback from openclaw agent (#112074) refactor: move provider transports into packages/ai behind a typed host port (#111669) fix(anthropic): complete transcript reverse-scan windows across short reads (#109431) ...
…ormed responses (openclaw#109986) * fix(plugin-sdk): guard provider catalog live URL parsing against malformed responses Provider catalog live discovery now wraps \ ew URL()\ calls in a \ ryParseUrl\ helper that returns undefined instead of throwing TypeError on malformed absolute URLs from API responses. Before: a malformed \ ext\ / \links.next\ URL or an unparseable fetch redirect target in the catalog response body crashes model discovery with an uncaught TypeError. After: malformed URLs are treated as absent (no next page), falling through to cursor-based pagination or completing the catalog. Co-Authored-By: Claude <[email protected]> * fix(plugin-sdk): return incomplete pagination when malformed next URL has no cursor fallback When a provider catalog response advertises a next page via the `next` or `links.next` field but the URL is malformed or cross-origin, the previous fix fell through to bodyAdvertisesMoreLiveModelCatalogPages which could silently return `complete` when has_more was absent or false. This truncated catalogs that use only link-based pagination. The fix returns `incomplete` when a provider-advertised next URL is unusable and no cursor-based fallback exists, surfacing a controlled error instead of silently dropping pages. Co-Authored-By: Claude <[email protected]> --------- Co-authored-by: Claude <[email protected]>
What Problem This Solves
Fixes an issue where
fetchLiveProviderModelRows/fetchLiveProviderModelIdswould crash with an uncaughtTypeErrorwhen a provider model catalog API returns a genuinely malformed absolute URL in itsnext/links.nextpagination field, or when the guarded fetch reports an unparseable redirect target (finalUrl).Why This Change Was Made
resolveLiveModelCatalogNextPageandfetchLiveProviderModelRowseach callednew URL()on external API response data without try/catch. The fix introduces atryParseUrlhelper that returnsundefinedon parse failures, matching the defensive pattern already used bywithoutMatrixStateAfterSyncParamin the Matrix transport (#109759).When a provider-advertised next URL is malformed or cross-origin, the fix attempts cursor-based pagination as a fallback, then returns the controlled
incompleteresult when no fallback remains — preventing silent catalog truncation.User Impact
Provider live model discovery survives misbehaving catalog APIs without crashing; a malformed pagination URL surfaces a controlled incomplete-pagination error instead of an uncaught TypeError or a silently truncated catalog.
Evidence
Before (upstream main — TypeError crash through real guarded fetch):
{"ok":false,"error":"TypeError: Invalid URL","label":"before-fix"}After (this branch — controlled incomplete-pagination error through real guarded fetch):
{"ok":false,"error":"Error: proof model discovery did not include a supported next page before the catalog completed","label":"after-fix"}The harness drives the real exported
fetchLiveProviderModelIdsthrough a loopback HTTP server using the productionfetchWithSsrFGuardandssrfPolicyFromHttpBaseUrlAllowedHostname. The malformednextURL contains a space in the hostname (http://exa mple.com/p2), which is a genuinely invalid absolute URL that triggers the nativenew URL()parse failure.Focused tests (24 passed):
New tests cover: malformed absolute
nextURL (incomplete-pagination error), malformed nestedlinks.nextURL, cursor fallback recovery from malformed URL, unparseablefinalUrl(cross-origin replay header fallback), and malformednextwithhas_more: true.What was not tested: Live provider catalog APIs returning malformed pagination URLs; the loopback harness proves the defensive parsing guard on the real exported function through the production guarded-HTTP stack.
🤖 Generated with Claude Code