DIYgod/RSSHub · error · InvalidParameterError

Invalid genre ranking type: ${type}

Error message

Invalid genre ranking type: ${type}

What it means

Thrown by parseGenreRankingType (syosetu/ranking.ts:208) as an InvalidParameterError when the genre-ranking `type` (format period_genre_novelType) is malformed OR the genre is one of the two explicitly-excluded values. Genre is a NUMERIC enum from the narou package. The validation rejects: invalid period, genre not in Genre enum, invalid novelType, genre === Genre.SonotaReplay, and genre === Genre.NonGenre (the latter two have no rankings on syosetu). novelType defaults to 'total' if omitted. Reached via /syosetu/ranking/genre/<type>.

Source

Thrown at lib/routes/syosetu/ranking.ts:208

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

    return { period, novelType };
}

function parseGenreRankingType(type: string): { period: RankingPeriod; genre: number; novelType: NovelType } {
    const [periodStr, genreStr, novelTypeStr = NovelType.TOTAL] = type.split('_', 3);

    const period = periodStr as RankingPeriod;
    const genre = Number(genreStr) as Genre;
    const novelType = novelTypeStr as NovelType;

    const isValid = [Object.values(RankingPeriod).includes(period), Object.values(Genre).includes(genre), Object.values(NovelType).includes(novelType), genre !== Genre.SonotaReplay, genre !== Genre.NonGenre].every(Boolean);

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

    return { period, genre, novelType };
}

async function handler(ctx: Context): Promise<Data> {
    const { listType, type } = ctx.req.param();
    const rankingType = listType as RankingType;
    const limit = Math.min(Number(ctx.req.query('limit') ?? 300), 300);

    const api = new NarouNovelFetch();
    const searchParams: SearchParams = {
        gzip: 5,
        lim: limit,
    };

    let rankingUrl: string;
    let rankingTitle: string;

View on GitHub (pinned to bed535e087)

Solutions

  1. Pick a valid numeric Genre from the route's parameters.type.options (which already filters out the two excluded genres).
  2. Use the format <period>_<genre>_<novelType>, where novelType is optional (defaults to total).

Example fix

// before (SonotaReplay / NonGenre are excluded)
GET /syosetu/ranking/genre/daily_<NonGenre>_total
// after (use a ranked genre)
GET /syosetu/ranking/genre/daily_<validGenre>_total
Defensive patterns

Strategy: validation

Validate before calling

import { Genre } from 'narou';
import { RankingPeriod, NovelType } from './types/ranking';

const EXCLUDED = new Set<Genre>([Genre.SonotaReplay, Genre.NonGenre]);

function isValidGenreType(type: string): boolean {
  const [p, g, n = NovelType.TOTAL] = type.split('_', 3);
  const genre = Number(g) as Genre;
  return Object.values(RankingPeriod).includes(p as RankingPeriod)
    && Object.values(Genre).includes(genre)
    && !EXCLUDED.has(genre)
    && Object.values(NovelType).includes(n as NovelType);
}

Type guard

import { Genre } from 'narou';

function isRankedGenre(genre: number): genre is Genre {
  const numericGenres = Object.values(Genre).filter((v): v is number => typeof v === 'number');
  return numericGenres.includes(genre)
    && genre !== Genre.SonotaReplay
    && genre !== Genre.NonGenre;
}

Prevention

When it happens

Trigger: Non-numeric genre; genre number outside the Genre enum; using SonotaReplay or NonGenre; unknown period or novelType; wrong segment order.

Common situations: Hand-typing a genre number; trying to rank the NonGenre or その他リプレイ categories which syosetu itself does not rank; confusing the genre number with the biggenre number.

Related errors


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