mirror of
https://github.com/Comfy-Org/comfy-typescript-sdk.git
synced 2026-11-04 23:47:27 +00:00
[PR #207] fix(assets): map a bodiless HEAD 429 on the dedup probe to rate_limited #208
Labels
No labels
audit:ai-readiness
audit:community
audit:github
audit:health-scoring
audit:policy
audit:release
audit:supply-chain
bug
cursor-review-pin
effort:medium
effort:small
effort:trivial
priority:nice-to-have
priority:recommended
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Comfy-Org/comfy-typescript-sdk#208
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/Comfy-Org/comfy-typescript-sdk/pull/207
Author: @mattmillerai
Created: 10/9/2026
Status: 🔄 Open
Base:
main← Head:be-19948-head-429-rate-limited📝 Commits (2)
02a2f4efix(assets): map a bodiless HEAD 429 on the dedup probe to rate_limitedcd9bbc8fix(assets): give a bodiless HEAD 401 on the dedup probe its Unauthorized message📊 Changes
5 files changed (+104 additions, -2 deletions)
View changed files
📝
CHANGELOG.md(+10 -0)📝
src/low/transport.test.ts(+33 -0)📝
src/low/transport.ts(+27 -1)📝
src/sdk/assets.test.ts(+14 -1)📝
test/support/stub-server.ts(+20 -0)📄 Description
ELI-5
Before uploading a file, the SDK asks the server "do you already have these bytes?" using a
HEADrequest. When the gateway rate-limits that question, it replies with a bare429and no body (HEADresponses never have one). The SDK then guessed what the429meant and picked "the job queue is full" (QueueFull), which is wrong. Now it reports a rate limit (code: "rate_limited") and keeps the server'sRetry-After.What changed
src/low/transport.ts—headAssetByHash: after the 200/404 checks, a bodiless401,403or429is looked up in a small status table (HEAD_REFUSALS) and thrown througherrorFromEnvelopewith a synthesized envelope plusretryAfterfromRetry-After. A429becomes{ code: "rate_limited", message: "Rate limited" }. Becauserate_limitedhas noBY_CODEentry, this is a plainApiError, which the SDK layer turns into a genericComfyErrorwithcode: "rate_limited". That matches how a429 rate_limitedwith a body already surfaces. A bodiless401/403is stillUnauthorized/Forbidden, but its message is nowUnauthorized/Forbiddeninstead ofHTTP 401/HTTP 403. The401was added after review: it is the refusal the spec actually declares for this operation. The doc comment explains that the code is built from the status because the refusal has no body.test/support/stub-server.ts: newheadStatus: 401 | 403 | 429 | nullandomitHeadRetryAftersettings. With them, the HEAD route answers with an empty body, and the 429 reusesretryAfterHeader.Retry-After: 7, 429 without it, 401, 403) and oneassets.fromBytes(...).commit()case. That case checks the result is aComfyErrorwithrate_limited, is notQueueFull, hasretryAfter7, and that no upload happened.CHANGELOG.md: added under Unreleased / Fixed.Not changed, as required:
CODE_BY_STATUS,retryThrottled, and the exported error classes. NoRateLimitedclass was added, so the surface-parity test is unchanged.Judgment calls
forbidden, messageForbidden), and after review the same for 401 (unauthorized,Unauthorized). The classes and codes are the same as before; only the message text changed.retryAfterthrough. It isnullunless the server sends the header, which matches whatparseOrRaisealready did.Provenance
pnpm test), including the 5 new casestransport.tschange reverted, the new 429/403 tests failpnpm check:sdk-parity(network), the Node 22/24 CI matrixResidual
429/403onHEAD /api/v2/assets/by-hash/{hash}is reproduced only by the stub server. I did not send traffic to the real platform gateway to trigger its rate limit or SSO refusal, because that is not a safe read-only check.403 sso_requiredon this probe is indistinguishable from a generic403. With no body, the SDK reportsforbidden. Tellingsso_requiredapart would need something other than the body, such as a response header. Bodiedsso_requiredhandling is tracked separately. This PR does not change it.queue_fullon a bodiless429, it needs the same change. I did not check the Python SDK here.spec/openapi.yamldoes not declare403/429on this operation. A separate upstream spec change adds them. This fix does not depend on it, and I did not edit the vendored spec.Retry-After(today it abortscommit()/submit(), as before this PR), and a typed error class for v2rate_limited(its obvious name collides with the routerRateLimitedexport).🤖 Generated with Claude Code
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.