DIYgod/RSSHub · error · InvalidParameterError

Novel not found in both APIs

Error message

Novel not found in both APIs

What it means

Thrown by fetchNovelInfo (syosetu/utils.ts:20) as an InvalidParameterError when BOTH the general (ncode.syosetu.com) and R18 (novel18.syosetu.com) narou search APIs return allcount === 0 for the given ncode. The two APIs are queried in parallel; the code picks the general result if its allcount is non-zero, else the R18 result. If neither has the novel, it does not exist (or the ncode is wrong). Used by the dev/chapter routes.

Source

Thrown at lib/routes/syosetu/utils.ts:20

import type { NarouSearchResult } from 'narou';
import { NarouNovelFetch, SearchBuilder, SearchBuilderR18 } from 'narou';

import { config } from '@/config';
import InvalidParameterError from '@/errors/types/invalid-parameter';
import type { DataItem } from '@/types';
import cache from '@/utils/cache';
import ofetch from '@/utils/ofetch';

export async function fetchNovelInfo(ncode: string): Promise<{ baseUrl: string; novel: NarouSearchResult }> {
    const api = new NarouNovelFetch();
    const [generalRes, r18Res] = await Promise.all([new SearchBuilder({ gzip: 5, of: 't-s-k-ga-nt-nu' }, api).ncode(ncode).execute(), new SearchBuilderR18({ gzip: 5, of: 't-s-k-ga-nt-nu' }, api).ncode(ncode).execute()]);

    const isGeneral = generalRes.allcount !== 0;
    const novelData = isGeneral ? generalRes : r18Res;
    const baseUrl = isGeneral ? 'https://ncode.syosetu.com' : 'https://novel18.syosetu.com';

    if (novelData.allcount === 0) {
        throw new InvalidParameterError('Novel not found in both APIs');
    }

    return {
        baseUrl,
        novel: novelData.values[0] as NarouSearchResult,
    };
}

export async function fetchChapterContent(chapterUrl: string, chapter?: number): Promise<DataItem> {
    return (await cache.tryGet(chapterUrl, async () => {
        const response = await ofetch(chapterUrl, {
            headers: {
                Cookie: 'over18=yes',
                'User-Agent': config.ua,
            },
        });

        const $ = load(response);

View on GitHub (pinned to bed535e087)

Solutions

  1. Verify the ncode by opening https://ncode.syosetu.com/<ncode>/ (general) or https://novel18.syosetu.com/<ncode>/ (R18) in a browser.
  2. Re-copy the ncode from the novel's URL — it is the path segment, lowercase, starting with a letter.

Example fix

// before (typo / wrong id)
GET /syosetu/dev/n1234zz
// after (verified ncode)
GET /syosetu/dev/n1234ab
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check the ncode shape before hitting the API.
// Narou ncodes are lowercase, start with a letter, then digits then letters.
function isPlausibleNcode(ncode: string): boolean {
  return typeof ncode === 'string'
    && ncode === ncode.toLowerCase()
    && /^[a-z]\d+[a-z]+$/.test(ncode);
}

Type guard

function isNcode(ncode: string): ncode is string {
  return typeof ncode === 'string'
    && ncode === ncode.toLowerCase()
    && /^[a-z]\d+[a-z]+$/.test(ncode);
}

Try / catch

try {
  await fetchNovelInfo(ncode);
} catch (e) {
  if (e instanceof InvalidParameterError && /not found in both APIs/i.test(e.message)) {
    // ncode does not exist on either general or R18 site
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing a malformed or non-existent ncode; the novel was deleted by its author; the ncode belongs to a private/draft novel; confusing the ncode with the numeric novel id.

Common situations: Typo in the ncode; following a stale link to a deleted novel; mixing up ncode (e.g. n1234ab) with the numeric id.

Related errors


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