pear-devs/pear-desktop · error · Error

Failed to parse response from MusixMatch API

Error message

Failed to parse response from MusixMatch API

What it means

'Failed to parse response from MusixMatch API' is thrown when the response body from a MusixMatch endpoint fails Zod validation against ResponseSchema[endpoint]. Before throwing, the provider logs 'Malformed response' with the raw response and the Zod error, so the actual mismatch is visible in the console. This almost always means MusixMatch changed their API shape or returned an HTML error/redirect page instead of JSON.

Source

Thrown at src/plugins/synced-lyrics/providers/MusixMatch.ts:241

      response && typeof response === 'object' &&
      'message' in response && response.message && typeof response.message === 'object' &&
      'header' in response.message && response.message.header && typeof response.message.header === 'object' &&
      'status_code' in response.message.header && typeof response.message.header.status_code === 'number' &&
      response.message.header.status_code === 401
    ) {
      await this.reinit();
      return this.query(endpoint, params);
    }

    const parsed = z
      .object({
        message: z.object({ body: ResponseSchema[endpoint] }),
      })
      .safeParse(response);

    if (!parsed.success) {
      console.error('Malformed response', response, parsed.error);
      throw new Error('Failed to parse response from MusixMatch API');
    }

    return parsed.data.message as R;
  }

  private savedTokenSchema = z.union([
    z.object({
      token: z.literal(null),
      expires: z.number().optional(),
    }),
    z.object({
      token: z.string(),
      expires: z.number(),
    }),
  ]);

  private key = 'ytm:synced-lyrics:mxm:token';
  private async init() {

View on GitHub (pinned to 1e2aac5706)

Solutions

  1. Read the console output of 'Malformed response' — the raw response and parsed.error pinpoint the failing field.
  2. If the token is stale/invalid, clear the cached token (localStorage key) and reinit() to get a fresh one.
  3. Update the corresponding ResponseSchema in MusixMatch.ts to match MusixMatch's current response shape (e.g. make fields optional or add new fields).
  4. If the response is HTML (rate limit/block), back off and retry later or disable the MusixMatch provider.

Example fix

// before (schema requires a field MusixMatch no longer always returns)
const LyricsSchema = z.object({ lyrics: z.object({ lyrics_body: z.string() }) });

// after (relax to optional with fallback)
const LyricsSchema = z.object({ lyrics: z.object({ lyrics_body: z.string().optional() }).optional() });
Defensive patterns

Strategy: fallback

Type guard

const isMusixMatchParseError = (e: unknown): boolean =>
  e instanceof Error && e.message === 'Failed to parse response from MusixMatch API';

Try / catch

try {
  const res = await provider.query(endpoint, params);
} catch (e) {
  if (isMusixMatchParseError(e)) {
    // schema drift or stale token: skip provider, try next lyrics source
    return nextProvider.query(params);
  }
  throw e;
}

Prevention

When it happens

Trigger: Any query() call (e.g. matcher.subtitle.get or track.search) where the JSON returned is missing expected fields, has nulls where the schema requires values, or where the token expired and the API returned an error payload that does not match the expected schema.

Common situations: MusixMatch shipping an API change (renamed/removed fields), an expired or invalid stored token causing error responses, rate limiting returning an unexpected body, or a CDN/captive portal injecting HTML. Check the preceding console.error output to see exactly which field failed.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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