DIYgod/RSSHub · error · Error

Douban 返回数据结构异常,可能触发反爬或限频。${details ? `上游信息:${details}` : ''

Error message

Douban 返回数据结构异常,可能触发反爬或限频。${details ? `上游信息:${details}` : ''}

What it means

Thrown by the Douban TV coming-soon route when the API response's `subjects` field is not an array. The route calls Douban's Frodo API (`frodo.douban.com/api/v2/tv/coming_soon`) with HMAC-signed requests. When Douban's anti-crawler or rate-limiter kicks in, the API returns an error object (with `msg`/`message`/`reason` fields) instead of the expected `subjects` array. The error message appends any upstream detail from those fields.

Source

Thrown at lib/routes/douban/tv/coming.ts:188

                    url: apiUrl,
                    searchParams,
                    headers: {
                        Accept: 'application/json',
                        'User-Agent': apiClientUa,
                    },
                });
                return response.data as ComingSoonResponse;
            } catch (error) {
                throw buildFetchError(error);
            }
        },
        config.cache.routeExpire,
        false
    )) as ComingSoonResponse;

    if (!Array.isArray(data.subjects)) {
        const details = data.msg || data.message || data.reason;
        throw new Error(`Douban 返回数据结构异常,可能触发反爬或限频。${details ? `上游信息:${details}` : ''}`);
    }
    if (data.subjects.length === 0) {
        throw new Error('Douban 返回空数据,可能触发反爬或限频。请稍后重试。');
    }

    const subscriptionCount = data.count ?? 0;
    const total = data.total ?? 0;
    const sortedSubjects = data.subjects.toSorted((a, b) => {
        if (sortBy === 'time') {
            const timeDiff = getSortTimestamp(a.pubdate) - getSortTimestamp(b.pubdate);
            if (timeDiff !== 0) {
                return timeDiff;
            }
            return getWishCount(b.wish_count) - getWishCount(a.wish_count);
        }
        const wishDiff = getWishCount(b.wish_count) - getWishCount(a.wish_count);
        if (wishDiff !== 0) {
            return wishDiff;

View on GitHub (pinned to bed535e087)

Solutions

  1. Wait and retry after a cooldown period — the route uses cache so the first successful response serves subsequent requests.
  2. If the apiKey/apiSecret are stale, check for updates in the RSSHub repository.
  3. Route through a residential proxy or run from a non-datacenter IP if IP-level blocking is suspected.
  4. Inspect the upstream detail in the error message for the specific Douban error code/reason.
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight check: verify the API key is still valid by making a test request
async function checkDoubanApiHealth(): Promise<boolean> {
    try {
        const resp = await fetch(`${apiUrl}?count=1&apiKey=${apiKey}`, {
            headers: { 'User-Agent': apiClientUa }
        });
        const data = await resp.json();
        return Array.isArray(data.subjects);
    } catch {
        return false;
    }
}

Type guard

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

Try / catch

try {
    const feed = await fetch(`${rsshubUrl}/douban/tv/coming`);
} catch (e) {
    if (e.message.includes('反爬或限频')) {
        // Wait and retry — Douban rate limits are temporary
        await new Promise(r => setTimeout(r, 60000));
        return fetch(`${rsshubUrl}/douban/tv/coming`);
    }
    throw e;
}

Prevention

When it happens

Trigger: Douban's Frodo API returns a rate-limit or anti-crawl error (e.g. {msg: 'rate limited', subjects: undefined}); the API key or signing algorithm has been deprecated/changed by Douban; the API endpoint structure has changed; the server IP is temporarily blocked.

Common situations: High request frequency triggers Douban rate limiting; the hardcoded apiKey/apiSecret has been revoked by Douban; RSSHub instance runs from a datacenter IP range that Douban blocks.

Related errors


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