DIYgod/RSSHub · error · InvalidParameterError

Invalid channel name

Error message

Invalid channel name

What it means

The 21财经 channel route fetches a remote webMenu.json from static.21jingji.com and verifies the requested channel `name` is a key in that live menu before composing the API URL. InvalidParameterError is thrown if the channel is not present, because the subsequent API call would be meaningless.

Source

Thrown at lib/routes/21caijing/channel.ts:57

    }

    return result;
};

export const handler = async (ctx: Context): Promise<Data> => {
    const { name = '热点' } = ctx.req.param();
    const limit = Number(ctx.req.query('limit') ?? '30');

    const domain = 'm.21jingji.com';
    const baseUrl = `https://${domain}`;
    const staticBaseUrl = 'https://static.21jingji.com';
    const menuUrl: string = new URL('m/webMenu.json', staticBaseUrl).href;

    const menuResponse = await ofetch(menuUrl);
    const menu = processMenu(menuResponse);

    if (!menu.hasOwnProperty(name)) {
        throw new InvalidParameterError('Invalid channel name');
    }

    const currentChannel = menu[name];

    const apiUrl: string = new URL(currentChannel.apiUrl, baseUrl).href;
    const targetUrl: string = new URL(`#/${currentChannel.url}`, baseUrl).href;
    const authUrl: string = new URL('reader/cbhChannelAuth', baseUrl).href;

    const targetResponse = await ofetch(targetUrl);
    const $: CheerioAPI = load(targetResponse);
    const language: string = $('html').attr('lang') ?? 'zh-CN';

    const authResponse = await ofetch(authUrl, {
        method: 'POST',
        responseType: 'json',
    });

    const response = await ofetch(apiUrl, {

View on GitHub (pinned to bed535e087)

Solutions

  1. Open https://static.21jingji.com/m/webMenu.json and copy an existing key verbatim.
  2. Fall back to the default by omitting the segment (defaults to '热点').
  3. If the menu endpoint itself moved, report it to maintainers — the URL may need updating.

Example fix

// before
/21caijing/channel/hotnews        // not a key in webMenu.json
// after
/21caijing/channel/热点             // or omit the segment
Defensive patterns

Strategy: try-catch

Validate before calling

// Cannot be fully pre-validated without fetching webMenu.json,
// but you can pre-flight it:
async function channelExists(name) {
  const menu = await ofetch('https://static.21jingji.com/m/webMenu.json');
  return Object.prototype.hasOwnProperty.call(processMenu(menu), name);
}

Type guard

function isInMenu(menu, name): name is string {
  return typeof name === 'string' && Object.prototype.hasOwnProperty.call(menu, name);
}

Try / catch

try {
  return await build21caijingFeed(name);
} catch (e) {
  if (e instanceof InvalidParameterError && /Invalid channel name/.test(e.message)) {
    // refresh the menu once and retry, else fall back to default '热点'
    return await build21caijingFeed('热点');
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling /21caijing/channel/:name with a value that is not a property of the fetched m/webMenu.json — a typo, a renamed channel, or a channel the app retired.

Common situations: The menu changed upstream (channel renamed/removed); copy-pasting a stale name; the default '热点' no longer being present after a redesign.

Related errors


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