DIYgod/RSSHub · error · Error

Failed to fetch channel data from Castbox

Error message

Failed to fetch channel data from Castbox

What it means

Thrown by the Castbox channel route when the upstream call to `https://everest.castbox.fm/data/channel/v3` returns a falsy or empty `.data` field. This is an upstream/API failure guard, not an input validation. The request itself may have succeeded (HTTP 200) but the body shape was unexpected.

Source

Thrown at lib/routes/castbox/channel.ts:65

    description: `Get the channel from the Castbox channel URL. For example, the URL of the channel "Lemonade Stand" is \`https://castbox.fm/channel/Lemonade-Stand-id6776228\`, where \`Lemonade-Stand-id6776228\` is the \`channel\` parameter.

You can use the RSSHub global \`limit\` query parameter to specify the maximum number of episodes to fetch from the Castbox API (defaults to 50). For example: \`/castbox/channel/Lemonade-Stand-id6776228?limit=100\`.`,
    maintainers: ['ananyatimalsina'],
    handler: async (ctx) => {
        const { channel } = ctx.req.param();
        const cid = channel.split('-id', 2)[1];

        if (!cid) {
            throw new Error('Invalid channel format. Missing -id');
        }

        const channelParams = { cid, r: 1, raw: 1, web: 1 };
        const { m: cm, n: cn, queryStr: cQuery } = getNonce(channelParams);

        const channelData = await ofetch(`https://everest.castbox.fm/data/channel/v3?${cQuery}&m=${cm}&n=${cn}`);

        if (!channelData?.data) {
            throw new Error('Failed to fetch channel data from Castbox');
        }

        const chData = channelData.data;
        const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit') as string) : 50;

        const epParams = { cid, limit, r: 1, raw: 1, web: 1 };
        const { m: em, n: en, queryStr: eQuery } = getNonce(epParams);

        const epData = await ofetch(`https://everest.castbox.fm/data/episode_list/v2?${eQuery}&m=${em}&n=${en}`);

        if (!epData?.data?.episode_list) {
            throw new Error('Failed to fetch episode list from Castbox');
        }

        const episodes = epData.data.episode_list;

        const items = episodes.map((ep: any) => {
            let enclosure_type = 'audio/mpeg';

View on GitHub (pinned to bed535e087)

Solutions

  1. Retry the request after a short interval — often transient.
  2. Verify the channel id by opening the castbox.fm URL in a browser; a deleted channel yields no data.
  3. If reproducing consistently across channels, the `getNonce` signing logic likely needs updating to match Castbox's current client.
  4. Inspect the raw `everest.castbox.fm/data/channel/v3` response (with the computed query string) to see the actual error body.
Defensive patterns

Strategy: try-catch

Type guard

function hasChannelData(r: unknown): r is { data: Record<string, unknown> } {
    return typeof r === 'object' && r !== null && 'data' in r && !!r.data;
}

Try / catch

try {
    const channelData = await ofetch(url);
    if (!channelData?.data) {
    // retry once, then surface a typed error
    }
} catch (e) {
    throw new Error(`Castbox channel API unreachable: ${(e as Error).message}`);
}

Prevention

When it happens

Trigger: Castbox API returns `{}` or an error envelope without a `data` key; the cid extracted from the URL is invalid/expired and Castbox returns an empty channel; rate limiting returns a 200 with an error body; the nonce/signing in `getNonce` is rejected silently.

Common situations: Castbox changes its nonce algorithm or API contract, the channel was deleted, network proxy strips the JSON body, or transient CDN error returning HTML parsed as JSON.

Related errors


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