Skip to content

fix: resources vanish from server pages when stored x402 response is invalid#775

Open
clawdbot-glitch003 wants to merge 1 commit into
Merit-Systems:mainfrom
clawdbot-glitch003:fix/resources-render-parse-failure
Open

fix: resources vanish from server pages when stored x402 response is invalid#775
clawdbot-glitch003 wants to merge 1 commit into
Merit-Systems:mainfrom
clawdbot-glitch003:fix/resources-render-parse-failure

Conversation

@clawdbot-glitch003
Copy link
Copy Markdown

Bug Report

Resources registered via the public.resources.register tRPC mutation can become invisible on server overview pages, even though they are correctly stored in the database with valid accepts data.

Reproduction

  1. Register an x402 V2 resource via the register mutation (e.g. from an automated publish pipeline)
  2. Visit the server page for that origin
  3. Expected: Resources appear in the "Resources" section
  4. Actual: "No Resources" empty state is shown, despite the sidebar showing the correct resource count

Root Cause

Two issues combine to cause this:

1. registerResource() stores response without validation (apps/scan/src/lib/resources.ts:140-143)

await upsertResourceResponse(
  resource.resource.id,
  (advisory.paymentRequiredBody ?? {}) as ParsedX402Response
);

When advisory.paymentRequiredBody is undefined or doesn't pass the Zod schema, {} gets stored in the ResourceResponse.response Json column. The ping route (app/api/resources/ping/route.ts:71-73) already validates before storing — this path skips that validation.

2. listOriginsWithResources() re-validates at render time and hides failures (apps/scan/src/services/db/resources/origin.ts:171-182)

resources: origin.resources.map(resource => {
  const response = parseX402Response(resource.response?.response);
  return {
    ...resource,
    ...response,  // spreads { success: false } when parse fails
  };
}),

The spread overwrites the resource with { success: false }. The UI component (origin-resources.tsx:39-41) filters to only show resources where resource.success === true && resource.accepts.length > 0, so any resource with a bad stored response disappears — even though its accepts data is correctly stored.

Fix

  1. Validate before storing: registerResource() now calls parseX402Response() before upsertResourceResponse(), matching the ping route pattern. Invalid responses are logged and skipped.

  2. Graceful render fallback: listOriginsWithResources() now falls back to { success: true, data: null } when the stored response fails to parse, so resources remain visible using their DB-level accepts data.

Impact

This affects any x402 resource registered via the register mutation where the stored response body doesn't pass strict Zod validation. The resource, its accepts, and its origin are all correctly stored — only the response rendering path is broken.

Test Plan

  • Register a V2 x402 resource via the register mutation
  • Verify it appears on the server overview page
  • Verify existing resources with valid stored responses still render correctly
  • Verify the ping route continues to work as before (it was already correct)

…led parse

Two bugs caused resources to disappear from server pages:

1. `registerResource()` stored `advisory.paymentRequiredBody` without validation,
   casting it directly as `ParsedX402Response`. When the body was undefined or
   malformed, `{}` was stored in the database. The ping route already validates
   with `parseX402Response()` before storing — this aligns the registration path
   with that pattern.

2. `listOriginsWithResources()` re-validated stored responses at render time via
   `parseX402Response()`, then spread the result (including `{ success: false }`)
   onto each resource. The UI filters out resources where `success !== true`,
   so any resource with a bad stored response became invisible — even though its
   accepts data was correctly stored in the database.

The fix:
- Validate `advisory.paymentRequiredBody` before storing; skip storage if invalid
- When stored response fails to parse at render time, fall back to
  `{ success: true, data: null }` so the resource remains visible using its
  DB-level accepts

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

vercel Bot commented Apr 14, 2026

@glitch003 is attempting to deploy a commit to the Merit Systems Team on Vercel.

A member of the Team first needs to authorize it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants