{"record":{"id":"1485fe49c588a0ff","repo":"DIYgod/RSSHub","slug":"failed-to-fetch-episode-list-from-castbox","errorCode":null,"errorMessage":"Failed to fetch episode list from Castbox","messagePattern":"Failed to fetch episode list from Castbox","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/routes/castbox/channel.ts","lineNumber":77,"sourceCode":"        const channelParams = { cid, r: 1, raw: 1, web: 1 };\n        const { m: cm, n: cn, queryStr: cQuery } = getNonce(channelParams);\n\n        const channelData = await ofetch(`https://everest.castbox.fm/data/channel/v3?${cQuery}&m=${cm}&n=${cn}`);\n\n        if (!channelData?.data) {\n            throw new Error('Failed to fetch channel data from Castbox');\n        }\n\n        const chData = channelData.data;\n        const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit') as string) : 50;\n\n        const epParams = { cid, limit, r: 1, raw: 1, web: 1 };\n        const { m: em, n: en, queryStr: eQuery } = getNonce(epParams);\n\n        const epData = await ofetch(`https://everest.castbox.fm/data/episode_list/v2?${eQuery}&m=${em}&n=${en}`);\n\n        if (!epData?.data?.episode_list) {\n            throw new Error('Failed to fetch episode list from Castbox');\n        }\n\n        const episodes = epData.data.episode_list;\n\n        const items = episodes.map((ep: any) => {\n            let enclosure_type = 'audio/mpeg';\n            if (ep.video === 1 || ep.url?.includes('.mp4')) {\n                enclosure_type = 'video/mp4';\n            } else if (ep.url?.includes('.m4a')) {\n                enclosure_type = 'audio/mp4';\n            }\n\n            return {\n                title: ep.title,\n                description: ep.description,\n                pubDate: parseDate(ep.release_date),\n                link: `https://castbox.fm/episode/${encodeURIComponent(ep.title)}-id${cid}-id${ep.eid}`,\n                enclosure_url: ep.url,","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/castbox/channel.ts#L59-L95","documentation":"Thrown by the Castbox channel route when the episode-list endpoint `https://everest.castbox.fm/data/episode_list/v2` returns a body whose `.data.episode_list` is missing or falsy. Distinct from the channel-data guard (it fires after channel data is confirmed). Plain `Error`.","triggerScenarios":"Channel exists but has zero episodes and Castbox omits the `episode_list` key entirely; API version bump removes `episode_list`; nonce rejection on the second call; `limit` query param out of accepted range causes Castbox to return an error envelope.","commonSituations":"Newly created channels with no published episodes, channels that are video-only on a different endpoint, or a breaking change in Castbox's `/episode_list/v2` response schema.","solutions":["Confirm the channel actually has episodes on castbox.fm.","Retry once to rule out transient API hiccup.","If all channels fail, the `getNonce` params (`{ cid, limit, r: 1, raw: 1, web: 1 }`) likely no longer match Castbox's expected signature — update them.","Dump the raw episode_list response body to see whether Castbox returns an error code/message."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function hasEpisodeList(r: unknown): r is { data: { episode_list: unknown[] } } {\n    return Boolean(r && typeof r === 'object' && (r as any).data?.episode_list);\n}","tryCatchPattern":"try {\n    const epData = await ofetch(episodeUrl);\n    if (!epData?.data?.episode_list) {\n    // retry once, then throw with the upstream body for diagnosis\n    }\n} catch (e) {\n    throw new Error(`Castbox episode API unreachable: ${(e as Error).message}`);\n}","preventionTips":["Confirm the channel actually has episodes on the live site before assuming an API bug.","Keep the `getNonce` parameter set in sync with Castbox's current web client.","Differentiate 'channel has no episodes' from 'API broke' — consider returning an empty feed for the former."],"tags":["upstream-api","network","response-shape","external-service"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}