Edit history

Transient KLIPY 429 causes GIF unfurl to fail permanently has not been edited, so there are no earlier versions.

Current version | Original by penguin
Show

Transient KLIPY 429 causes GIF unfurl to fail permanently

Reproduction steps

The issue appears to be intermittent and is not reliably reproducible.
  1. Configure a KLIPY Production API key on a self-hosted Fluxer instance.
  2. Use KLIPY GIFs normally in chat.
  3. Occasionally, a GIF message remains as a plain https://klipy.com/gifs/... link instead of being unfurled into a GIF embed.
4 Check the worker and internal service logs around the time of the failed message.
  1. The failed unfurl correlates with KLIPY returning HTTP 429.
I observed two failed unfurls during normal usage. Other KLIPY GIFs worked normally again shortly afterwards.

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:
Unfurling URLs
No URLs were successfully unfurled
Job completed successfully
At the same timestamps, the unfurl service logged:
KLIPY direct API lookup returned non-200 status
status: 429
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.

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:
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"}
Matching KLIPY responses:
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"}
Successful unfurl a few seconds later:
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"}
Direct request to KLIPY using the Production key:
> 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
No Retry-After header was present in the response.