DIYgod/RSSHub · error · NotFoundError

LSD token not found

Error message

LSD token not found

What it means

Thrown by Threads (Meta) profile scraping when the regex cannot extract the LSD (Login Session Data) CSRF token from the profile HTML. The token is required for authenticated GraphQL calls to Threads' internal API. A NotFoundError indicates the page markup no longer contains the expected `"LSD",[],{"token":"..."}` pattern.

Source

Thrown at lib/routes/threads/utils.ts:37

            Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
            'Accept-Encoding': 'gzip, br',
            'Accept-Language': 'zh-CN,zh;q=0.9',
            'Cache-Control': 'no-cache',
            Pragma: 'no-cache',
            'Sec-Fetch-Dest': 'document',
            'Sec-Fetch-Mode': 'navigate',
            'Sec-Fetch-Site': 'none',
            'Sec-Fetch-User': '?1',
            'Upgrade-Insecure-Requests': '1',
        },
    });

    const $ = load(response);
    const data = $('script:contains("LSD"):first').text();
    const lsd = data.match(/"LSD",\[\],\{"token":"([\w@-]+)"\},/)?.[1];

    if (!lsd) {
        throw new NotFoundError('LSD token not found');
    }

    return { lsd };
};

const getUserId = async (user: string): Promise<string> => {
    const result = await cache.tryGet(`threads:userId:${user}`, async () => {
        const response = await ofetch(profileUrl(user), {
            headers: {
                'User-Agent': USER_AGENT,
                Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
                'Accept-Encoding': 'gzip, br',
                'Accept-Language': 'zh-CN,zh;q=0.9',
                'Cache-Control': 'no-cache',
                Pragma: 'no-cache',
                'Sec-Fetch-Dest': 'document',
                'Sec-Fetch-Mode': 'navigate',
                'Sec-Fetch-Site': 'none',

View on GitHub (pinned to bed535e087)

Solutions

  1. Verify the profile URL still returns the expected HTML by reproducing the ofetch with the same headers in isolation.
  2. Update the regex on line 34 to match Threads' current LSD token serialization (open the page, search the bundle for `LSD`).
  3. If Threads now gates the page behind login, switch the route to an authenticated flow or a different API surface.
  4. Add a retry with a different User-Agent / locale to dodge interstitials.

Example fix

// before
const lsd = data.match(/"LSD",\[\],\{"token":"([\w@-]+)"\},/)?.[1];
// after (loosen the matcher to current bundle shape)
const lsd = data.match(/"LSD"[^}]*"token":"([\w@-]+)"/)?.[1];
Defensive patterns

Strategy: try-catch

Validate before calling

const hasLsdShape = (html: string) => /"LSD"[^}]*"token":"[\w@-]+"/.test(html);
const html = await ofetch(profileUrl(user), { headers });
if (!hasLsdShape(html)) throw new Error('Threads page lacks LSD token — bundle changed or interstitial served');

Type guard

const isLsdToken = (v: unknown): v is string => typeof v === 'string' && /^[\w@-]+$/.test(v);

Try / catch

try { const { lsd } = await extractTokens(user); /* use lsd */ }
catch (e) { if (e instanceof NotFoundError) { /* fall back to alt API or surface 503 */ } else throw e; }

Prevention

When it happens

Trigger: The ofetch to https://www.threads.com/@{user} returns HTML whose inline scripts do not contain the LSD token string, so the regex match on line 34 yields undefined and line 36-37 throws. This happens when Threads changes its bundler output, serves a login-wall/consent page, or rate-limits the request.

Common situations: Threads rotates its client bundle and the LSD token key/shape changes; an unsupported region gets redirected to an interstitial; the mobile User-Agent is fingerprinted and served a different page; ofetch follows a redirect to a login page.

Related errors


AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12). Data as JSON: /api/errors/c49bd98c6eb39041. Report an issue: GitHub.