Summary
EasyEDA's component API rate-limits by IP and answers with HTTP 403 once
tripped — not 429, and with no Retry-After. fetchEasyEDAComponent treats any
non-success response as a lookup failure, so the whole batch surfaces as:
Async effect error in PcbFootprintStringRender "load-lib-footprint":
Error: Failed to search for the component
at fetchEasyEDAComponent (...)
at async JlcPcbPartsEngine.fetchPartCircuitJson (...)
at async jlcpcb (...)
The message points at the component, which sends you looking for a bad part
number. The part is fine; the request was throttled.
Reproduction
A board with ~10 footprint="jlcpcb:C…" strings resolves them concurrently on
render and reliably trips the limit. It reproduces directly against the API:
U="https://easyeda.com/api/products/C11702/components?version=6.4.19.5"
for i in $(seq 1 20); do curl -s -o /dev/null -w "%{http_code} " "$U"; done
Output goes 200 200 … 403 403 403. Recovery measured on a single IP:
immediately: 403
+ 20s -> 403
+ 40s -> 403
+ 60s -> 403
+ 80s -> 403
+100s -> 403
+120s -> 200
So roughly a two-minute cooldown.
Things it is not
Worth stating, because both look plausible and both are wrong:
- Not the part. Every LCSC id I tried behaved identically, and all resolve
fine once the cooldown expires.
- Not the User-Agent. Mid-cooldown every UA 403s — browser strings,
curl/8.4.0, a custom string, and no UA header at all. Before the limit is
tripped, all of them return 200. I initially misread partial data as
UA-based blocking; a wider sweep ruled it out.
Impact
- A warm local cache hides it, so it fails for new contributors and in CI while
working on the maintainer's machine.
- Failures cascade: one throttled batch fails every footprint in it.
- The error text sends users hunting for a nonexistent part-number problem.
Suggestions
- Throttle/serialise parts-engine fetches instead of firing the batch at once.
- Retry 403 with backoff — the cooldown is short and bounded.
- Distinguish "rate limited" from "not found" in the error text. Right now they
are indistinguishable, and only the second one is the user's problem.
- Consider proxying through tscircuit infrastructure, as
modelcdn.tscircuit.com already does for 3D models, so one shared cache
absorbs the limit rather than every user's IP hitting it directly.
Related
easyeda-converter has a long run of [Cxxxxxxx] Failed to import from JLCPCB
issues (#223, #240, #262, #268, #272, #275, #288, #314, …), each filed against a
specific part. It may be worth checking how many are actually this, since a
throttled lookup is indistinguishable from a genuinely missing part in the
current message.
Versions
tscircuit CLI 0.0.2132, @tscircuit/core 0.0.1484, @tscircuit/props 0.0.587
- also reproduced in the browser runtime, bun 1.3.14, macOS arm64
Summary
EasyEDA's component API rate-limits by IP and answers with HTTP 403 once
tripped — not 429, and with no
Retry-After.fetchEasyEDAComponenttreats anynon-success response as a lookup failure, so the whole batch surfaces as:
The message points at the component, which sends you looking for a bad part
number. The part is fine; the request was throttled.
Reproduction
A board with ~10
footprint="jlcpcb:C…"strings resolves them concurrently onrender and reliably trips the limit. It reproduces directly against the API:
Output goes
200 200 … 403 403 403. Recovery measured on a single IP:So roughly a two-minute cooldown.
Things it is not
Worth stating, because both look plausible and both are wrong:
fine once the cooldown expires.
curl/8.4.0, a custom string, and no UA header at all. Before the limit istripped, all of them return 200. I initially misread partial data as
UA-based blocking; a wider sweep ruled it out.
Impact
working on the maintainer's machine.
Suggestions
are indistinguishable, and only the second one is the user's problem.
modelcdn.tscircuit.comalready does for 3D models, so one shared cacheabsorbs the limit rather than every user's IP hitting it directly.
Related
easyeda-converterhas a long run of[Cxxxxxxx] Failed to import from JLCPCBissues (#223, #240, #262, #268, #272, #275, #288, #314, …), each filed against a
specific part. It may be worth checking how many are actually this, since a
throttled lookup is indistinguishable from a genuinely missing part in the
current message.
Versions
tscircuitCLI 0.0.2132,@tscircuit/core0.0.1484,@tscircuit/props0.0.587