Reproduction steps
The issue appears to be intermittent and is not reliably reproducible.
- Configure a KLIPY Production API key on a self-hosted Fluxer instance.
- Use KLIPY GIFs normally in chat.
- Occasionally, a GIF message remains as a plain https://klipy.com/gifs/... link instead of being unfurled into a GIF embed.
- The failed unfurl correlates with KLIPY returning HTTP 429.
Expected behaviour
A transient HTTP 429 response from KLIPY should not permanently leave the message without an embed.
Ideally, the unfurl could be retried later or otherwise recover from a temporary KLIPY rate-limit response, instead of permanently leaving the original URL as a plain link.
Actual behaviour
When KLIPY returns HTTP 429 during the unfurl, Fluxer immediately completes the unfurl job without producing an embed.
The message then remains permanently as a plain KLIPY link.
For two affected messages, the worker logged:
At the same timestamps, the unfurl service logged:
A few seconds later, another KLIPY unfurl completed successfully with embedCount=1.
The configured key is a KLIPY Production key. I also copied the Production key directly from the KLIPY dashboard and tested the KLIPY API manually. The direct request also returned HTTP 429.
Unfurling URLs
No URLs were successfully unfurled
Job completed successfully
KLIPY direct API lookup returned non-200 status
status: 429
Build information
Canary Desktop 2026.1103.194246, Web 2026.1104.153913, Linux 7.2.15-200.fc44.x86_64 (x64), Electron 44.10.0, Chrome 152.0.7977.169, Node 24.22.1, Locale en-US
Evidence
I asked about this in the Fluxer development server first. Moderator Tarek suggested filing a bug report and asked me to include the response from a direct curl -v request to the KLIPY API, so I have included that below.
Two failed unfurls:
Matching KLIPY responses:
Successful unfurl a few seconds later:
Direct request to KLIPY using the Production key:
No Retry-After header was present in the response.
worker | {"level":"info","time":"2026-11-04T18:28:40.774Z","messageId":"1567606526959419392","urlCount":1,"skippedUrlCount":0,"msg":"Unfurling URLs"}
worker | {"level":"info","time":"2026-11-04T18:28:41.093Z","messageId":"1567606526959419392","urlsAttempted":1,"msg":"No URLs were successfully unfurled"}
worker | {"level":"info","time":"2026-11-04T18:28:42.250Z","messageId":"1567606533158600704","urlCount":1,"skippedUrlCount":0,"msg":"Unfurling URLs"}
worker | {"level":"info","time":"2026-11-04T18:28:42.529Z","messageId":"1567606533158600704","urlsAttempted":1,"msg":"No URLs were successfully unfurled"}
unfurl | {"timestamp":"2026-11-04T18:28:41.014750Z","level":"WARN","fields":{"message":"KLIPY direct API lookup returned non-200 status","status":429},"target":"fluxer_unfurl::resolvers::klipy"}
unfurl | {"timestamp":"2026-11-04T18:28:42.476122Z","level":"WARN","fields":{"message":"KLIPY direct API lookup returned non-200 status","status":429},"target":"fluxer_unfurl::resolvers::klipy"}
gifs | {"timestamp":"2026-11-04T18:28:42.408482Z","level":"WARN","fields":{"message":"handler returned error","error":"KLIPY registershare failed with status 429 Too Many Requests"},"target":"fluxer_svc::combined"}
worker | {"level":"info","time":"2026-11-04T18:28:51.648Z","messageId":"1567606572572475392","urlCount":1,"skippedUrlCount":0,"msg":"Unfurling URLs"}
worker | {"level":"info","time":"2026-11-04T18:28:51.899Z","messageId":"1567606572572475392","embedCount":1,"msg":"Handled extractEmbeds successfully"}
> GET /api/v1/[REDACTED]/gifs/items?slugs=hello-wave-97 HTTP/2
> Host: api.klipy.com
< HTTP/2 429
< content-type: text/html; charset=UTF-8
< cf-cache-status: BYPASS
< server: cloudflare
< via: 1.1 google
429 Too Many Requests
Comments
No comments yet.