pear-devs/pear-desktop · error · Error

bad HTTPStatus(${response.statusText})

Error message

bad HTTPStatus(${response.statusText})

What it means

The LRCLib lyrics provider searches lrclib.net; if the first HTTP response (artist/track/album query) returns a non-OK status, it throws an error embedding response.statusText. This is a plain network/HTTP failure against the LRCLib API.

Source

Thrown at src/plugins/synced-lyrics/providers/LRCLib.ts:34

    album,
    songDuration,
    tags,
  }: SearchSongInfo): Promise<LyricResult | null> {
    let query = new URLSearchParams({
      artist_name: artist,
      track_name: title,
    });

    query.set('album_name', album!);
    if (query.get('album_name') === 'undefined') {
      query.delete('album_name');
    }

    let url = `${this.baseUrl}/api/search?${query.toString()}`;
    let response = await fetch(url);

    if (!response.ok) {
      throw new Error(`bad HTTPStatus(${response.statusText})`);
    }

    let data = (await response.json()) as LRCLIBSearchResponse;
    if (!data || !Array.isArray(data)) {
      throw new Error(`Expected an array, instead got ${typeof data}`);
    }

    if (data.length === 0) {
      if (!config()?.showLyricsEvenIfInexact) {
        return null;
      }

      // Try to search with the alternative title (original language)
      const trackName = alternativeTitle || title;
      query = new URLSearchParams({ q: `${trackName}` });
      url = `${this.baseUrl}/api/search?${query.toString()}`;

      response = await fetch(url);

View on GitHub (pinned to 1e2aac5706)

Solutions

  1. Retry with backoff — LRCLib rate limits are often transient
  2. Wrap the provider call and fall back to another provider (Megalobiz, Genius) or show no lyrics
  3. Cache successful lyric lookups to reduce request volume
  4. Check https://lrclib.net directly to distinguish outage from local network issues

Example fix

// before
const result = await lrclib.search(info);

// after
let result: LyricResult | null = null;
try { result = await lrclib.search(info); }
catch (e) { if (!/bad HTTPStatus/.test(e.message)) throw e; result = await megalobiz.search(info); }
Defensive patterns

Strategy: retry

Try / catch

const withRetry = async <T>(fn: () => Promise<T>, n = 3) => {
  for (let i = 0; ; i++) {
    try { return await fn(); }
    catch (e) {
      if (i >= n - 1 || !/bad HTTPStatus/.test(e.message)) throw e;
      await new Promise(r => setTimeout(r, 1000 * 2 ** i));
    }
  }
};
const r = await withRetry(() => lrclib.search(info));

Prevention

When it happens

Trigger: lrclib.net being down or returning 5xx; 429 rate limiting from too many lyric lookups; 4xx from bad query params; DNS/TLS failures surface as fetch rejects (different error), but any non-2xx status triggers this; proxy or firewall rewriting responses.

Common situations: Rapid song switching triggering rate limits; LRCLib outages; corporate networks blocking the API; offline usage.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of pear-devs/pear-desktop@1e2aac5706 (2026-08-27). Data as JSON: /api/errors/bc0c5ba0f9c79942. Report an issue: GitHub.