DIYgod/RSSHub · error · Error

Error occurred, please refresh the page or try again after l

Error message

Error occurred, please refresh the page or try again after logging back into your account

What it means

Plain Error thrown by the Xueqiu column handler after calling GET /statuses/original/timeline.json. The handler obtained an anonymous cookie via a cookieJar GET to the homepage and parsed SNOWMAN_TARGET from the column page, but the timeline API returned an object whose list field is falsy — Xueqiu's anti-crawler rejected the anonymous session. The message instructs the user to refresh or log in.

Source

Thrown at lib/routes/xueqiu/column.ts:60

    const pageData = await got(pageUrl, {
        cookieJar,
    });
    const { window } = new JSDOM(pageData.data, {
        runScripts: 'dangerously',
    });
    const SNOWMAN_TARGET = window.SNOWMAN_TARGET;

    const { data } = await got(`${baseUrl}/statuses/original/timeline.json`, {
        cookieJar,
        searchParams: {
            user_id: id,
            page: 1,
        },
    });

    if (!data.list) {
        throw new Error('Error occurred, please refresh the page or try again after logging back into your account');
    }

    const items = data.list.map((item) => ({
        title: item.title,
        description: item.description,
        pubDate: parseDate(item.created_at, 'x'),
        link: `${baseUrl}${item.target}`,
        author: SNOWMAN_TARGET.screen_name,
    }));

    return {
        title: `${SNOWMAN_TARGET.screen_name} - 雪球`,
        link: pageUrl,
        description: SNOWMAN_TARGET.description,
        item: items,
    };
}

View on GitHub (pinned to bed535e087)

Solutions

  1. Retry after a short cooldown — Xueqiu anti-crawler is often transient.
  2. Run RSSHub from a residential/non-datacenter IP, or front it with a proxy that Xueqiu does not flag.
  3. Reduce request frequency / raise config.cache.routeExpire for this route.
  4. If persistent, set a valid logged-in Xueqiu cookie and rework the handler to send it (the route currently relies on the anonymous cookieJar, which is increasingly insufficient).
  5. Inspect data (log it) to see the exact Xueqiu error_code and adjust accordingly.

Example fix

// before
if (!data.list) {
    throw new Error('Error occurred, please refresh the page or try again after logging back into your account');
}

// after — surface Xueqiu's own error code so the cause is diagnosable
if (!data.list) {
    throw new Error(`Xueqiu rejected the timeline request (code=${data.error_code ?? 'unknown'}: ${data.error_description ?? 'no list returned'}). The anonymous cookie may be insufficient; retry or supply a logged-in cookie.`);
}
Defensive patterns

Strategy: retry

Validate before calling

// Nothing to validate before the call — the anonymous cookie is obtained inline.
// Best preflight: verify the column page actually exposed SNOWMAN_TARGET
if (!SNOWMAN_TARGET || !SNOWMAN_TARGET.screen_name) {
    throw new Error('Xueqiu did not expose SNOWMAN_TARGET on the column page; the anonymous session was likely blocked.');
}

Type guard

function hasTimelineList(data: unknown): data is { list: unknown[] } {
    return typeof data === 'object' && data !== null && Array.isArray((data as any).list);
}

Try / catch

// Xueqiu anti-bot is intermittent; retry with a fresh cookieJar
for (let attempt = 0; attempt < 3; attempt++) {
    const freshJar = new CookieJar();
    await got(baseUrl, { cookieJar: freshJar });
    const { data } = await got(`${baseUrl}/statuses/original/timeline.json`, { cookieJar: freshJar, searchParams: { user_id: id, page: 1 } });
    if (data.list) return data;
    await new Promise((r) => setTimeout(r, (attempt + 1) * 1500));
}
throw new Error('Xueqiu repeatedly refused the timeline request; supply a logged-in cookie or reduce frequency.');

Prevention

When it happens

Trigger: got(baseUrl) seeds the cookieJar, got(pageUrl) loads the column HTML and runs JSDOM to extract SNOWMAN_TARGET, then got('/statuses/original/timeline.json') returns successfully (HTTP 200) but with a body like {error_description, error_code} or {list: null} because Xueqiu flagged the request as a bot. The !data.list guard then fires.

Common situations: Self-hosted RSSHub hitting Xueqiu from a datacenter IP that Xueqiu rate-limits; the anonymous token (xq_a_token) expired between requests; Xueqiu changed its anti-bot to require a logged-in cookie for column timelines; high request frequency tripped throttling.

Related errors


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