What happens
Every PDF download link minted on rxresu.me right now is rejected by the endpoint that serves it. Minting and verification disagree on the payload field name, and the verifying side is the code in this repo.
Reproduced today at 17:33Z on 5.3.1:
- Ask for a link (I used the
download_resume_pdf MCP tool; the response says expiresInSeconds: 600).
- Load it immediately.
$ curl -i "$downloadUrl"
HTTP/2 401
Unauthorized
Six attempts on one link, then 24 in parallel on another, all 401. Same key, same account, same machine, nothing changed in between.
The token is fresh, and it is not an expiry
Decoded payload of a link minted five seconds before the request:
{
"v": 1,
"resuleId": "01a0a997-...",
"userId": "019bef8d-...",
"target": "resume",
"expiresAt": 1789839822731,
"issuedAt": 1789839222731
}
minted 17:33:42Z, requested 17:33:47Z, expires 17:43:42Z. Ids truncated.
resuleId is not the field the verifier reads. In packages/api/src/features/resume/pdf-download-url.ts at v5.3.1:
if (typeof payload.resumeId !== "string" || payload.resumeId.length === 0) return null;
That returns malformed, and apps/server/src/http/resume-pdf.ts maps everything other than expired to 401, so from outside it is indistinguishable from a bad signature. I checked out of paranoia: a code search over this repo finds verifyResumePdfDownloadToken in five places and resuleId in none, so whatever minted that payload is not the code in the tree.
It worked earlier today, which points at a skewed deployment
At 13:13Z a link minted the same way downloaded a PDF normally. That token carries the identical resuleId payload. So the verifier changed under me during the day: what served /api/resumes/:id/pdf this morning accepted this payload and what serves it now does not. That reads like a rollout where the minting side is still on older code and the verifying side moved to 5.3.1, and links started failing as the old instances drained. It would also be worth knowing whether the minting path is meant to be shared, since the same resuleId string appears on both the MCP and the web-facing links I have seen.
Meanwhile, in the same seconds
GET /api/openapi/resumes -> 200
GET /api/openapi/resumes/<id>/pdf -> 200, 44546 bytes of PDF
GET /api/health -> 200, database healthy, uptime 2.3 days
So rendering, storage and the account are fine. Only the token route rejects its own output. The API key route is what I use now, though it means every client that follows the downloadUrl the API hands back is broken, including the MCP tool that exists to produce it.
Possibly related
Earlier in the afternoon, for roughly half an hour, the same API key got 401 from /api/openapi/resumes, /mcp refused the initialize handshake with 401, and one MCP write call failed and then succeeded on retry. All of it cleared without a key rotation. If a rollout was in flight then too, that would fit, but I have not tested it.
Happy to keep probing the hosted instance while it reproduces.
What happens
Every PDF download link minted on rxresu.me right now is rejected by the endpoint that serves it. Minting and verification disagree on the payload field name, and the verifying side is the code in this repo.
Reproduced today at 17:33Z on 5.3.1:
download_resume_pdfMCP tool; the response saysexpiresInSeconds: 600).Six attempts on one link, then 24 in parallel on another, all 401. Same key, same account, same machine, nothing changed in between.
The token is fresh, and it is not an expiry
Decoded payload of a link minted five seconds before the request:
{ "v": 1, "resuleId": "01a0a997-...", "userId": "019bef8d-...", "target": "resume", "expiresAt": 1789839822731, "issuedAt": 1789839222731 }minted 17:33:42Z, requested 17:33:47Z, expires 17:43:42Z. Ids truncated.
resuleIdis not the field the verifier reads. Inpackages/api/src/features/resume/pdf-download-url.tsat v5.3.1:That returns
malformed, andapps/server/src/http/resume-pdf.tsmaps everything other thanexpiredto 401, so from outside it is indistinguishable from a bad signature. I checked out of paranoia: a code search over this repo findsverifyResumePdfDownloadTokenin five places andresuleIdin none, so whatever minted that payload is not the code in the tree.It worked earlier today, which points at a skewed deployment
At 13:13Z a link minted the same way downloaded a PDF normally. That token carries the identical
resuleIdpayload. So the verifier changed under me during the day: what served/api/resumes/:id/pdfthis morning accepted this payload and what serves it now does not. That reads like a rollout where the minting side is still on older code and the verifying side moved to 5.3.1, and links started failing as the old instances drained. It would also be worth knowing whether the minting path is meant to be shared, since the sameresuleIdstring appears on both the MCP and the web-facing links I have seen.Meanwhile, in the same seconds
So rendering, storage and the account are fine. Only the token route rejects its own output. The API key route is what I use now, though it means every client that follows the
downloadUrlthe API hands back is broken, including the MCP tool that exists to produce it.Possibly related
Earlier in the afternoon, for roughly half an hour, the same API key got 401 from
/api/openapi/resumes,/mcprefused the initialize handshake with 401, and one MCP write call failed and then succeeded on retry. All of it cleared without a key rotation. If a rollout was in flight then too, that would fit, but I have not tested it.Happy to keep probing the hosted instance while it reproduces.