{"record":{"id":"044cc8297f344f4b","repo":"pear-devs/pear-desktop","slug":"failed-to-get-token","errorCode":null,"errorMessage":"Failed to get token","messagePattern":"Failed to get token","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/plugins/synced-lyrics/providers/MusixMatch.ts","lineNumber":271,"sourceCode":"      token: z.string(),\n      expires: z.number(),\n    }),\n  ]);\n\n  private key = 'ytm:synced-lyrics:mxm:token';\n  private async init() {\n    const { token, expires } = this.savedTokenSchema.parse(\n      JSON.parse(localStorage.getItem(this.key) ?? '{ \"token\": null }'),\n    );\n    if (token && expires > Date.now()) {\n      this.token = token;\n      return;\n    }\n\n    localStorage.removeItem(this.key);\n\n    this.token = await this.getToken();\n    if (!this.token) throw new Error('Failed to get token');\n\n    localStorage.setItem(\n      this.key,\n      JSON.stringify({ token: this.token, expires: Date.now() + (60 * 1000) }),\n    );\n  }\n\n  private tokenSchema = z.object({\n    message: z.object({\n      body: z\n        .object({\n          user_token: z.string(),\n        })\n        .optional(),\n    }),\n  });\n  private async getToken() {\n    const endpoint = 'token.get';","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/pear-devs/pear-desktop/blob/1e2aac5706c870c93ed74ba8727ae8390d3b0fa5/src/plugins/synced-lyrics/providers/MusixMatch.ts#L253-L289","documentation":"'Failed to get token' is thrown by MusixMatch's init() when getToken() returns a falsy value — i.e. the provider could not extract a valid token from MusixMatch's token endpoint. init() first checks a localStorage-cached token (valid for 60 seconds), removes it if expired, then fetches a fresh one. Because the constructor kicks off init, this error typically surfaces on the first query() call via 'Token not initialized' or as an unhandled rejection.","triggerScenarios":"First use of the MusixMatch provider, or 60s after the last token was cached, when the network request for the token fails or the returned content doesn't match savedTokenSchema (z.union).","commonSituations":"No internet/DNS failure, MusixMatch changing the token endpoint or the token page's markup, corporate proxy blocking the domain, or the extracted token value being empty. Also fires whenever reinit() is called after the cached entry was removed.","solutions":["Verify network connectivity and that the MusixMatch token URL used in getToken() is still reachable.","Log the raw token response in getToken() and compare it against savedTokenSchema; update the parsing if MusixMatch changed the format.","If token fetch is inherently unreliable in your environment, disable the MusixMatch provider and fall back to other lyrics providers.","Catch the init failure and schedule reinit() with backoff instead of letting the rejection propagate."],"exampleFix":"// before\nthis.token = await this.getToken();\nif (!this.token) throw new Error('Failed to get token');\n\n// after\nthis.token = await this.getToken();\nif (!this.token) {\n  console.warn('MusixMatch token fetch failed; provider disabled until reinit');\n  throw new Error('Failed to get token');\n}","handlingStrategy":"try-catch","validationCode":"// preflight reachability before relying on the provider\nasync function canReachMusixMatch(): Promise<boolean> {\n  try {\n    await fetch(MUSIXMATCH_TOKEN_URL, { method: 'HEAD' });\n    return true;\n  } catch {\n    return false;\n  }\n}","typeGuard":"const isTokenFetchFailure = (e: unknown): boolean =>\n  e instanceof Error && e.message === 'Failed to get token';","tryCatchPattern":"try {\n  await provider.reinit();\n} catch (e) {\n  if (isTokenFetchFailure(e)) {\n    provider.enabled = false; // or skip provider for this session\n    return fallbackProvider;\n  }\n  throw e;\n}","preventionTips":["Catch initPromise at construction time so the rejection never becomes unhandled.","Retry reinit() with backoff on transient network failures.","Disable the MusixMatch provider via config when running in restricted networks."],"tags":["musixmatch","token","initialization","network","synced-lyrics"],"backgroundTag":"auth-token-fetch-failed","analyzedSha":"1e2aac5706c870c93ed74ba8727ae8390d3b0fa5","analyzedAt":"2026-08-27T20:01:08.614Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}