pear-devs/pear-desktop · error · Error

Token not initialized

Error message

Token not initialized

What it means

MusixMatch provider throws 'Token not initialized' when query() is invoked before the async token initialization has completed or if initialization failed to set a token. The method awaits this.initPromise and then checks this.token, so any init failure (e.g. 'Failed to get token') surfaces here as this error on subsequent API calls. It indicates the provider was never able to authenticate against the MusixMatch API.

Source

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

      this.cookie = 'x-mxm-user-id=';
      localStorage.removeItem(this.key);
      this.initPromise = this.init();
      await this.initPromise;
    }
  }

  // god I love typescript generics, they're so useful
  public async query<
    T extends Endpoint,
    R = {
      header: { status_code: number };
      body: T extends keyof typeof ResponseSchema
        ? z.infer<(typeof ResponseSchema)[T]>
        : unknown;
    },
  >(endpoint: T, params: Params[T]): Promise<R> {
    await this.initPromise;
    if (!this.token) throw new Error('Token not initialized');

    const url = `${this.baseUrl}${endpoint}`;

    const clonedParams = new URLSearchParams(
      Object.assign(
        {
          app_id: this.app_id,
          format: 'json',
          usertoken: this.token,
        },
        <Record<string, string>>params,
      ),
    );

    const [, json, headers] = await netFetch(`${url}?${clonedParams}`, {
      headers: { Cookie: this.cookie },
    });

View on GitHub (pinned to 1e2aac5706)

Solutions

  1. Check network access to the MusixMatch token endpoint and retry (call reinit()) once connectivity is restored.
  2. Clear the cached token entry in localStorage (this.key) and call reinit() to force a fresh token fetch.
  3. Inspect getToken()/savedTokenSchema parsing — if MusixMatch changed their page structure, update the token extraction logic.
  4. Ensure you await the provider's initialization (or the first query) before showing results, so init errors surface clearly instead of this secondary error.

Example fix

// before
const lyrics = await provider.query('matcher.lyrics.get', { q_track: '...' });

// after
try {
  const lyrics = await provider.query('matcher.lyrics.get', { q_track: '...' });
} catch (e) {
  if (e instanceof Error && e.message === 'Token not initialized') {
    await provider.reinit();
    // retry once after re-initialization
  }
}
Defensive patterns

Strategy: retry

Validate before calling

// before querying, ensure the provider initialized successfully
await provider.initPromise; // rethrows init failure early, or:
if (!provider.token) {
  await provider.reinit();
}

Type guard

const isTokenNotInitialized = (e: unknown): boolean =>
  e instanceof Error && e.message === 'Token not initialized';

Try / catch

try {
  const res = await provider.query('matcher.subtitle.get', params);
} catch (e) {
  if (isTokenNotInitialized(e)) {
    await provider.reinit();
    return provider.query('matcher.subtitle.get', params); // one retry
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling any lyrics lookup (this.data()/query()) before init() finishes, after init() threw 'Failed to get token', or after the cached token was removed from localStorage and reinit failed (network error or changed token endpoint).

Common situations: Offline or proxied environment blocking the token fetch, MusixMatch changing their token scraping endpoint/HTML structure, corrupted localStorage entry under this.key, or racing the provider's construction against an immediate query call.

Related errors


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