DIYgod/RSSHub · error · Error

Failed to retrieve manga meta from MangaDex API.

Error message

Failed to retrieve manga meta from MangaDex API.

What it means

Thrown when a bulk manga-metadata fetch (GET /manga?ids[]=...&includes[]=...&limit=...) returns data.result === 'error'. Unlike the single-manga path it uses a generic message rather than rethrowing data.errors[0].detail, so the underlying MangaDex error is hidden. Result is cached under a hashed key built from the de-duplicated id list.

Source

Thrown at lib/routes/mangadex/_feed.ts:90

 */
export async function getMangaMetaByIds(ids: string[], needCover: boolean = true, lang?: string | string[]): Promise<Map<string, { id: string; title: string; description: string; cover?: string }>> {
    const deDuplidatedIds = [...new Set(ids)].toSorted((a, b) => a.localeCompare(b));
    const includes = needCover ? ['cover_art'] : [];

    const rawMangaMetas = (await cache.tryGet(
        `mangadex:manga-meta:${md5(deDuplidatedIds.join(''))}`, // shorten the key
        async () => {
            const { data } = await got.get(
                constants.API.MANGA_META.slice(0, -1) +
                    toQueryString({
                        ids: deDuplidatedIds,
                        includes,
                        limit: deDuplidatedIds.length,
                    })
            );

            if (data.result === 'error') {
                throw new Error('Failed to retrieve manga meta from MangaDex API.');
            }
            return data.data;
        }
    )) as any[];

    const languages = [...(typeof lang === 'string' ? [lang] : lang || []), ...(await getFilteredLanguages())].filter(Boolean);

    const map = new Map<string, { id: string; title: string; description: string; cover?: string }>();
    for (const rawMangaMeta of rawMangaMetas) {
        const id = rawMangaMeta.id;

        const titles = {
            ...rawMangaMeta.attributes.title,
            ...Object.fromEntries(rawMangaMeta.attributes.altTitles.flatMap((element) => Object.entries(element))),
        };

        const title = firstMatch(titles, [...languages, rawMangaMeta.attributes.originalLanguage]) as string;

View on GitHub (pinned to bed535e087)

Solutions

  1. Reduce the batch size of manga ids sent to getMangaMetaByIds (chunk to <=100 per request).
  2. Filter out non-UUID ids before calling the bulk endpoint.
  3. Re-throw data.errors[0].detail (as the single-id path does) so the real MangaDex error is visible.
  4. Clear the hashed cache key if a transient API error got cached.

Example fix

// before
if (data.result === 'error') {
    throw new Error('Failed to retrieve manga meta from MangaDex API.');
}
// after
if (data.result === 'error') {
    throw new Error(`Failed to retrieve manga meta from MangaDex API: ${data.errors?.[0]?.detail ?? 'unknown error'}`);
}
Defensive patterns

Strategy: validation

Validate before calling

const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
function sanitizeIdList(ids: string[], max = 100) {
    const clean = ids.filter((id) => UUID_RE.test(id));
    if (clean.length > max) {
        throw new Error(`Bulk manga request exceeds ${max} ids`);
    }
    return clean;
}

Type guard

const isMangadexErrorResult = (v: unknown): v is { result: 'error'; errors: Array<{ detail: string }> } =>
    typeof v === 'object' && v !== null && (v as { result?: string }).result === 'error';

Try / catch

try {
    metas = await getMangaMetaByIds(ids);
} catch (e) {
    // fall back to per-id fetches so one bad id does not break the batch
    metas = await Promise.all(ids.map((id) => getMangaMeta(id).catch(() => null)));
}

Prevention

When it happens

Trigger: Bulk GET https://api.mangadex.org/manga?ids=<list> where MangaDex returns an error result: too many ids in one request (over the endpoint limit), any id is malformed, or rate limiting.

Common situations: User follows/lists returned more manga ids than the bulk endpoint accepts; one invalid id in the list poisons the whole batch; transient API error cached for the route expire duration.

Related errors


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