DIYgod/RSSHub · error · InvalidParameterError

Bad timeRange range. See <a href="https://docs.rsshub.app/ro

Error message

Bad timeRange range. See <a href="https://docs.rsshub.app/routes/new-media#wang-yi-xin-wen-pai-hang-bang">docs</a>

What it means

Thrown by the 163 (NetEase) news ranking route when the supplied category/type/time triple is a combination 163.com does not publish. The route's description enumerates which time ranges each ranking type supports, and this guard rejects requests the upstream page would render empty rather than silently returning nothing.

Source

Thrown at lib/routes/163/news/rank.ts:127

新闻分类:

| 全站  | 新闻 | 娱乐          | 体育   | 财经  | 科技 | 汽车 | 女人 | 房产  | 游戏 | 旅游   | 教育 |
| ----- | ---- | ------------- | ------ | ----- | ---- | ---- | ---- | ----- | ---- | ------ | ---- |
| whole | news | entertainment | sports | money | tech | auto | lady | house | game | travel | edu  |`,
};

async function handler(ctx) {
    const category = ctx.req.param('category') || 'whole';
    const type = ctx.req.param('type') || 'click';
    const time = ctx.req.param('time') || 'day';

    const cfg = config[category];
    if (!cfg) {
        throw new InvalidParameterError('Bad category. See <a href="https://docs.rsshub.app/routes/new-media#wang-yi-xin-wen-pai-hang-bang">docs</a>');
    }
    if ((category !== 'whole' && type === 'click' && time === 'month') || (category === 'whole' && type === 'click' && time === 'hour') || (type === 'follow' && time === 'hour')) {
        throw new InvalidParameterError('Bad timeRange range. See <a href="https://docs.rsshub.app/routes/new-media#wang-yi-xin-wen-pai-hang-bang">docs</a>');
    }

    const currentUrl = category === 'money' ? cfg.link : `${rootUrl}${cfg.link}`;
    const response = await got({
        method: 'get',
        url: currentUrl,
        responseType: 'buffer',
    });

    const $ = load(iconv.decode(response.data, 'gbk'));

    const list = $('div.tabContents')
        .eq(timeRange[time].index + (category === 'whole' ? (type === 'click' ? -1 : 2) : type === 'click' ? 0 : 2))
        .find('table tbody tr td a')
        .toArray()
        .map((item): DataItem => {
            const $item = $(item);

View on GitHub (pinned to bed535e087)

Solutions

  1. For non-whole click rankings use hour/day/week (never month).
  2. For whole click rankings use day/week/month (never hour).
  3. For follow rankings always use day/week/month (never hour).
  4. Consult the route description's tip block for the canonical matrix.

Example fix

// before
/163/news/rank/news/click/month   // 163 has no monthly click rank for sub-categories
// after
/163/news/rank/news/click/week
Defensive patterns

Strategy: validation

Validate before calling

const VALID = {
  wholeClick: new Set(['day', 'week', 'month']),     // whole + click
  subClick:   new Set(['hour', 'day', 'week']),      // non-whole + click
  follow:     new Set(['day', 'week', 'month']),     // any + follow
};
function isValid163Rank(category, type, time) {
  if (type === 'follow') return VALID.follow.has(time);
  if (category === 'whole') return VALID.wholeClick.has(time);
  return VALID.subClick.has(time);
}

Type guard

function is163Time(c, t, time): boolean {
  return (t === 'follow' ? ['day','week','month']
    : c === 'whole' ? ['day','week','month']
    : ['hour','day','week']).includes(time);
}

Prevention

When it happens

Trigger: Hitting /163/news/rank/<category>/<type>/<time> where: (a) category is not 'whole' but type='click' and time='month'; (b) category='whole' with type='click' and time='hour'; (c) any category with type='follow' and time='hour'.

Common situations: Copy-pasting a working URL and swapping only one segment (e.g. changing category from 'whole' to 'news' but keeping time='month'), or assuming the follow (跟贴) ranking supports an hourly breakdown like the click ranking does.

Related errors


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