DIYgod/RSSHub · error · InvalidParameterError

Invalid ranking type: ${type}

Error message

Invalid ranking type: ${type}

What it means

Thrown by parseRankingType (syosetu/ranking-r18.ts:132) as an InvalidParameterError when the R18 ranking `type` (format period_novelType) has an invalid component. CRITICAL difference from the general ranking: the R18 RankingPeriod enum (types/ranking-r18.ts:10) EXCLUDES 'total' — valid R18 periods are daily, weekly, monthly, quarter, yearly only. novelType (NovelType) is the same: total, t, r, er. Reached via /syosetu/rankingr18/<sub>/<type>. The R18 enum is file-local and looks nearly identical to the general one, which is the main footgun.

Source

Thrown at lib/routes/syosetu/ranking-r18.ts:132

        },
        {
            source: ['mnlt.syosetu.com/rank/bllist/type/:type'],
            target: '/rankingr18/mnlt-bl/:type',
        },
        ...getBest5RadarItems(),
    ],
};

function parseRankingType(type: string): { period: RankingPeriod; novelType: NovelType } {
    const [periodStr, novelTypeStr] = type.split('_', 2);

    const period = periodStr as RankingPeriod;
    const novelType = novelTypeStr as NovelType;

    const isValid = [Object.values(RankingPeriod).includes(period), Object.values(NovelType).includes(novelType)].every(Boolean);

    if (!isValid) {
        throw new InvalidParameterError(`Invalid ranking type: ${type}`);
    }

    return {
        period: periodStr as RankingPeriod,
        novelType: novelTypeStr as NovelType,
    };
}

function getRankingTitle(type: string, limit: number): string {
    const { period, novelType } = parseRankingType(type);
    return `${periodToJapanese[period]}${novelTypeToJapanese[novelType]}ランキング BEST${limit}`;
}

async function handler(ctx: Context): Promise<Data> {
    const { sub, type } = ctx.req.param();
    const baseUrl = `https://${sub === SyosetuSub.MOONLIGHT_BL ? SyosetuSub.MOONLIGHT : sub}.syosetu.com`;
    const rankingUrl = `${baseUrl}/rank/list/type/${type}`;
    const api = new NarouNovelFetch();

View on GitHub (pinned to bed535e087)

Solutions

  1. Use a valid R18 period — daily, weekly, monthly, quarter, or yearly — never 'total'.
  2. Keep the <period>_<novelType> order, with novelType in {total, t, r, er}.

Example fix

// before (total period is invalid for R18)
GET /syosetu/rankingr18/noc/total_total
// after
GET /syosetu/rankingr18/noc/daily_total
Defensive patterns

Strategy: validation

Validate before calling

import { RankingPeriod, NovelType } from './types/ranking-r18';

// R18 RankingPeriod EXCLUDES 'total' — do not import the general one by mistake.
const PERIODS = Object.values(RankingPeriod);
const NOVEL_TYPES = Object.values(NovelType);

function isValidR18Type(type: string): boolean {
  const [p, n] = type.split('_', 2);
  return PERIODS.includes(p as RankingPeriod)
    && NOVEL_TYPES.includes(n as NovelType);
}

Type guard

function isR18RankingType(type: string): boolean {
  const [p, n] = type.split('_', 2);
  return ['daily','weekly','monthly','quarter','yearly'].includes(p) // NO 'total'
    && ['total','t','r','er'].includes(n);
}

Prevention

When it happens

Trigger: Using 'total' as the period (e.g. total_t or total_total) — not supported on R18 sites; wrong segment order (t_daily); unknown novelType; missing the novelType segment.

Common situations: Copying a general-ranking URL (/ranking/list/total_total) into the r18 route; assuming the two RankingPeriod enums are the same.

Related errors


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