{"record":{"id":"42fa4c73cccf3f06","repo":"pear-devs/pear-desktop","slug":"failed-to-parse-response-from-musixmatch-api","errorCode":null,"errorMessage":"Failed to parse response from MusixMatch API","messagePattern":"Failed to parse response from MusixMatch API","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/plugins/synced-lyrics/providers/MusixMatch.ts","lineNumber":241,"sourceCode":"      response && typeof response === 'object' &&\n      'message' in response && response.message && typeof response.message === 'object' &&\n      'header' in response.message && response.message.header && typeof response.message.header === 'object' &&\n      'status_code' in response.message.header && typeof response.message.header.status_code === 'number' &&\n      response.message.header.status_code === 401\n    ) {\n      await this.reinit();\n      return this.query(endpoint, params);\n    }\n\n    const parsed = z\n      .object({\n        message: z.object({ body: ResponseSchema[endpoint] }),\n      })\n      .safeParse(response);\n\n    if (!parsed.success) {\n      console.error('Malformed response', response, parsed.error);\n      throw new Error('Failed to parse response from MusixMatch API');\n    }\n\n    return parsed.data.message as R;\n  }\n\n  private savedTokenSchema = z.union([\n    z.object({\n      token: z.literal(null),\n      expires: z.number().optional(),\n    }),\n    z.object({\n      token: z.string(),\n      expires: z.number(),\n    }),\n  ]);\n\n  private key = 'ytm:synced-lyrics:mxm:token';\n  private async init() {","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/pear-devs/pear-desktop/blob/1e2aac5706c870c93ed74ba8727ae8390d3b0fa5/src/plugins/synced-lyrics/providers/MusixMatch.ts#L223-L259","documentation":"'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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the console output of 'Malformed response' — the raw response and parsed.error pinpoint the failing field.","If the token is stale/invalid, clear the cached token (localStorage key) and reinit() to get a fresh one.","Update the corresponding ResponseSchema in MusixMatch.ts to match MusixMatch's current response shape (e.g. make fields optional or add new fields).","If the response is HTML (rate limit/block), back off and retry later or disable the MusixMatch provider."],"exampleFix":"// before (schema requires a field MusixMatch no longer always returns)\nconst LyricsSchema = z.object({ lyrics: z.object({ lyrics_body: z.string() }) });\n\n// after (relax to optional with fallback)\nconst LyricsSchema = z.object({ lyrics: z.object({ lyrics_body: z.string().optional() }).optional() });","handlingStrategy":"fallback","validationCode":null,"typeGuard":"const isMusixMatchParseError = (e: unknown): boolean =>\n  e instanceof Error && e.message === 'Failed to parse response from MusixMatch API';","tryCatchPattern":"try {\n  const res = await provider.query(endpoint, params);\n} catch (e) {\n  if (isMusixMatchParseError(e)) {\n    // schema drift or stale token: skip provider, try next lyrics source\n    return nextProvider.query(params);\n  }\n  throw e;\n}","preventionTips":["Check console for the 'Malformed response' log — it contains the Zod issue list.","Keep response schemas tolerant (optional fields) since MusixMatch is an undocumented API.","Chain multiple lyrics providers so one provider's schema break doesn't kill lyric lookup."],"tags":["musixmatch","zod","schema-validation","api-response","synced-lyrics"],"backgroundTag":"schema-validation-failed","analyzedSha":"1e2aac5706c870c93ed74ba8727ae8390d3b0fa5","analyzedAt":"2026-08-27T20:01:08.614Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}